From 339baf9bfa15b8bceea272c2436debf1a83c3ae0 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Feb 2023 11:23:19 +0000 Subject: [PATCH 001/191] feat: add parsing of qemu disks into struct --- proxmox/config_qemu_disk.go | 266 +++++++++++++++++++++++++++++ proxmox/config_qemu_disk_ide.go | 105 ++++++++++++ proxmox/config_qemu_disk_sata.go | 115 +++++++++++++ proxmox/config_qemu_disk_scsi.go | 249 +++++++++++++++++++++++++++ proxmox/config_qemu_disk_virtio.go | 165 ++++++++++++++++++ proxmox/util.go | 9 + proxmox/util_test.go | 28 +++ 7 files changed, 937 insertions(+) create mode 100644 proxmox/config_qemu_disk.go create mode 100644 proxmox/config_qemu_disk_ide.go create mode 100644 proxmox/config_qemu_disk_sata.go create mode 100644 proxmox/config_qemu_disk_scsi.go create mode 100644 proxmox/config_qemu_disk_virtio.go create mode 100644 proxmox/util_test.go diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go new file mode 100644 index 00000000..5e110e96 --- /dev/null +++ b/proxmox/config_qemu_disk.go @@ -0,0 +1,266 @@ +package proxmox + +import ( + "math" + "strconv" + "strings" +) + +type IsoFile struct { + Storage string + File string + // Size can only be retrieved, setting it has no effect + Size string +} + +type QemuCdRom struct { + Iso *IsoFile + // Passthrough and File are mutually exclusive + Passthrough bool +} + +func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { + if !settings.Passthrough { + return &QemuCdRom{ + Iso: &IsoFile{ + Storage: settings.Storage, + File: settings.File, + Size: settings.Size, + }, + } + } + return &QemuCdRom{Passthrough: false} +} + +type qemuCdRom struct { + // "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M" + Passthrough bool + Storage string + // FileType is only set for Cloud init drives, this value will be used to check if it is a normal cdrom or cloud init drive. + FileType string + File string + Size string +} + +func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { + var isCdRom bool + for _, e := range settings { + if e[0] == "media" { + if e[1] == "cdrom" { + isCdRom = true + break + } + } + } + if !isCdRom { + return nil + } + if settings[0][0] == "none" { + return &qemuCdRom{} + } + if settings[0][0] == "cdrom" { + return &qemuCdRom{Passthrough: true} + } + tmpStorage := strings.Split(settings[0][0], ":") + if len(tmpStorage) > 1 { + tmpFile := strings.Split(settings[0][0], "/") + if len(tmpFile) == 2 { + tmpFileType := strings.Split(tmpFile[1], ".") + if len(tmpFileType) > 1 { + fileType := tmpFileType[len(tmpFileType)-1] + if fileType == "iso" { + for _, e := range settings { + if e[0] == "size" { + return &qemuCdRom{ + Storage: tmpStorage[0], + File: tmpFile[1], + Size: e[1], + } + } + } + } else { + return &qemuCdRom{ + Storage: tmpStorage[0], + File: tmpFile[1], + FileType: fileType, + } + } + } + } + } + return nil +} + +type QemuCloudInitDisk struct { + Storage string + FileType string +} + +func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { + return &QemuCloudInitDisk{ + Storage: settings.Storage, + FileType: settings.FileType, + } +} + +// TODO add enum +type QemuDiskAsyncIO string + +type QemuDiskBandwidth struct { + ReadLimit_Data QemuDisk_Bandwidth_Data + WriteLimit_Data QemuDisk_Bandwidth_Data + ReadLimit_Iops QemuDisk_Bandwidth_Iops + WriteLimit_Iops QemuDisk_Bandwidth_Iops +} + +type QemuDisk_Bandwidth_Data struct { + Concurrent float32 + Burst float32 +} + +type QemuDisk_Bandwidth_Iops struct { + Concurrent uint + Burst uint +} + +// TODO add enum +type QemuDiskCache string + +// TODO add enum +type QemuDiskFormat string + +func (QemuDiskFormat) mapToStruct(setting string) QemuDiskFormat { + settings := strings.Split(setting, ".") + if len(settings) < 2 { + return "" + } + return QemuDiskFormat(settings[len(settings)-1]) +} + +type qemuDisk struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + // TODO custom type + // File is only set for Passthrough. + File string + Format QemuDiskFormat + IOThread bool + ReadOnly bool + Replicate bool + Size uint + // TODO custom type + // Storage is only set for Disk + Storage string +} + +// Maps all the disk related settings +func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { + if len(settings) == 0 { + return nil + } + disk := qemuDisk{Backup: true} + + if settings[0][0][0:1] == "/" { + disk.File = settings[0][0] + } else { + // "test2:105/vm-105-disk-53.qcow2, + disk.Storage = strings.Split(settings[0][0], ":")[0] + disk.Format = QemuDiskFormat("").mapToStruct(settings[0][0]) + } + + for _, e := range settings { + if e[0] == "aio" { + disk.AsyncIO = QemuDiskAsyncIO(e[1]) + continue + } + if e[0] == "backup" { + disk.Backup, _ = strconv.ParseBool(e[1]) + continue + } + if e[0] == "cache" { + disk.Cache = QemuDiskCache(e[1]) + continue + } + if e[0] == "discard" { + disk.Discard, _ = strconv.ParseBool(e[1]) + continue + } + if e[0] == "iops_rd" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.ReadLimit_Iops.Concurrent = uint(tmp) + } + if e[0] == "iops_rd_max" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.ReadLimit_Iops.Burst = uint(tmp) + } + if e[0] == "iops_wr" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.WriteLimit_Iops.Concurrent = uint(tmp) + } + if e[0] == "iops_wr_max" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.WriteLimit_Iops.Burst = uint(tmp) + } + if e[0] == "iothread" { + disk.IOThread, _ = strconv.ParseBool(e[1]) + continue + } + if e[0] == "mbps_rd" { + tmp, _ := strconv.ParseFloat(e[1], 32) + disk.Bandwidth.ReadLimit_Data.Concurrent = float32(math.Round(tmp*100) / 100) + } + if e[0] == "mbps_rd_max" { + tmp, _ := strconv.ParseFloat(e[1], 32) + disk.Bandwidth.ReadLimit_Data.Burst = float32(math.Round(tmp*100) / 100) + } + if e[0] == "mbps_wr" { + tmp, _ := strconv.ParseFloat(e[1], 32) + disk.Bandwidth.WriteLimit_Data.Concurrent = float32(math.Round(tmp*100) / 100) + } + if e[0] == "mbps_wr_max" { + tmp, _ := strconv.ParseFloat(e[1], 32) + disk.Bandwidth.WriteLimit_Data.Burst = float32(math.Round(tmp*100) / 100) + } + if e[0] == "replicate" { + disk.Replicate, _ = strconv.ParseBool(e[1]) + continue + } + if e[0] == "ro" { + disk.ReadOnly, _ = strconv.ParseBool(e[1]) + continue + } + if e[0] == "size" { + diskSize, _ := strconv.Atoi(strings.TrimSuffix(e[1], "G")) + disk.Size = uint(diskSize) + continue + } + if e[0] == "ssd" { + disk.EmulateSSD, _ = strconv.ParseBool(e[1]) + } + } + return &disk +} + +type QemuStorages struct { + Ide *QemuIdeDisks + Sata *QemuSataDisks + Scsi *QemuScsiDisks + VirtIO *QemuVirtIODisks +} + +func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { + storage := QemuStorages{ + Ide: QemuIdeDisks{}.mapToStruct(params), + Sata: QemuSataDisks{}.mapToStruct(params), + Scsi: QemuScsiDisks{}.mapToStruct(params), + VirtIO: QemuVirtIODisks{}.mapToStruct(params), + } + if storage.Ide != nil || storage.Sata != nil || storage.Scsi != nil || storage.VirtIO != nil { + return &storage + } + return nil +} diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go new file mode 100644 index 00000000..9db3ba5b --- /dev/null +++ b/proxmox/config_qemu_disk_ide.go @@ -0,0 +1,105 @@ +package proxmox + +type QemuIdeDisk struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + Replicate bool + Size uint + Storage string +} + +type QemuIdeDisks struct { + Disk_0 *QemuIdeStorage + Disk_1 *QemuIdeStorage + Disk_2 *QemuIdeStorage + Disk_3 *QemuIdeStorage +} + +func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { + disks := QemuIdeDisks{} + var structPopulated bool + if _, isSet := params["ide0"]; isSet { + disks.Disk_0 = QemuIdeStorage{}.mapToStruct(params["ide0"].(string)) + structPopulated = true + } + if _, isSet := params["ide1"]; isSet { + disks.Disk_1 = QemuIdeStorage{}.mapToStruct(params["ide1"].(string)) + structPopulated = true + } + if _, isSet := params["ide2"]; isSet { + disks.Disk_2 = QemuIdeStorage{}.mapToStruct(params["ide2"].(string)) + structPopulated = true + } + if _, isSet := params["ide3"]; isSet { + disks.Disk_3 = QemuIdeStorage{}.mapToStruct(params["ide3"].(string)) + structPopulated = true + } + if structPopulated { + return &disks + } + return nil +} + +type QemuIdePassthrough struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + File string + Replicate bool + Size uint +} + +type QemuIdeStorage struct { + CdRom *QemuCdRom + CloudInit *QemuCloudInitDisk + Disk *QemuIdeDisk + Passthrough *QemuIdePassthrough +} + +func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { + settings := splitStringOfSettings(param) + tmpCdRom := qemuCdRom{}.mapToStruct(settings) + if tmpCdRom != nil { + if tmpCdRom.FileType == "" { + return &QemuIdeStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} + } else { + return &QemuIdeStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} + } + } + + tmpDisk := qemuDisk{}.mapToStruct(settings) + if tmpDisk == nil { + return nil + } + if tmpDisk.File == "" { + return &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + }} + } + return &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + }} +} diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go new file mode 100644 index 00000000..ac1555c9 --- /dev/null +++ b/proxmox/config_qemu_disk_sata.go @@ -0,0 +1,115 @@ +package proxmox + +type QemuSataDisk struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + Replicate bool + Size uint + Storage string +} + +type QemuSataDisks struct { + Disk_0 *QemuSataStorage + Disk_1 *QemuSataStorage + Disk_2 *QemuSataStorage + Disk_3 *QemuSataStorage + Disk_4 *QemuSataStorage + Disk_5 *QemuSataStorage +} + +func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { + disks := QemuSataDisks{} + var structPopulated bool + if _, isSet := params["sata0"]; isSet { + disks.Disk_0 = QemuSataStorage{}.mapToStruct(params["sata0"].(string)) + structPopulated = true + } + if _, isSet := params["sata1"]; isSet { + disks.Disk_1 = QemuSataStorage{}.mapToStruct(params["sata1"].(string)) + structPopulated = true + } + if _, isSet := params["sata2"]; isSet { + disks.Disk_2 = QemuSataStorage{}.mapToStruct(params["sata2"].(string)) + structPopulated = true + } + if _, isSet := params["sata3"]; isSet { + disks.Disk_3 = QemuSataStorage{}.mapToStruct(params["sata3"].(string)) + structPopulated = true + } + if _, isSet := params["sata4"]; isSet { + disks.Disk_4 = QemuSataStorage{}.mapToStruct(params["sata4"].(string)) + structPopulated = true + } + if _, isSet := params["sata5"]; isSet { + disks.Disk_5 = QemuSataStorage{}.mapToStruct(params["sata5"].(string)) + structPopulated = true + } + if structPopulated { + return &disks + } + return nil +} + +type QemuSataPassthrough struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + File string + Replicate bool + Size uint +} + +type QemuSataStorage struct { + CdRom *QemuCdRom + CloudInit *QemuCloudInitDisk + Disk *QemuSataDisk + Passthrough *QemuSataPassthrough +} + +func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { + settings := splitStringOfSettings(param) + tmpCdRom := qemuCdRom{}.mapToStruct(settings) + if tmpCdRom != nil { + if tmpCdRom.FileType == "" { + return &QemuSataStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} + } else { + return &QemuSataStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} + } + } + + tmpDisk := qemuDisk{}.mapToStruct(settings) + if tmpDisk == nil { + return nil + } + if tmpDisk.File == "" { + return &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + }} + } + return &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + }} +} diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go new file mode 100644 index 00000000..5aa56e0b --- /dev/null +++ b/proxmox/config_qemu_disk_scsi.go @@ -0,0 +1,249 @@ +package proxmox + +type QemuScsiDisk struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + IOThread bool + ReadOnly bool + Replicate bool + Size uint + Storage string +} + +type QemuScsiDisks struct { + Disk_0 *QemuScsiStorage + Disk_1 *QemuScsiStorage + Disk_2 *QemuScsiStorage + Disk_3 *QemuScsiStorage + Disk_4 *QemuScsiStorage + Disk_5 *QemuScsiStorage + Disk_6 *QemuScsiStorage + Disk_7 *QemuScsiStorage + Disk_8 *QemuScsiStorage + Disk_9 *QemuScsiStorage + Disk_10 *QemuScsiStorage + Disk_11 *QemuScsiStorage + Disk_12 *QemuScsiStorage + Disk_13 *QemuScsiStorage + Disk_14 *QemuScsiStorage + Disk_15 *QemuScsiStorage + Disk_16 *QemuScsiStorage + Disk_17 *QemuScsiStorage + Disk_18 *QemuScsiStorage + Disk_19 *QemuScsiStorage + Disk_20 *QemuScsiStorage + Disk_21 *QemuScsiStorage + Disk_22 *QemuScsiStorage + Disk_23 *QemuScsiStorage + Disk_24 *QemuScsiStorage + Disk_25 *QemuScsiStorage + Disk_26 *QemuScsiStorage + Disk_27 *QemuScsiStorage + Disk_28 *QemuScsiStorage + Disk_29 *QemuScsiStorage + Disk_30 *QemuScsiStorage +} + +func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { + disks := QemuScsiDisks{} + var structPopulated bool + if _, isSet := params["scsi0"]; isSet { + disks.Disk_0 = QemuScsiStorage{}.mapToStruct(params["scsi0"].(string)) + structPopulated = true + } + if _, isSet := params["scsi1"]; isSet { + disks.Disk_1 = QemuScsiStorage{}.mapToStruct(params["scsi1"].(string)) + structPopulated = true + } + if _, isSet := params["scsi2"]; isSet { + disks.Disk_2 = QemuScsiStorage{}.mapToStruct(params["scsi2"].(string)) + structPopulated = true + } + if _, isSet := params["scsi3"]; isSet { + disks.Disk_3 = QemuScsiStorage{}.mapToStruct(params["scsi3"].(string)) + structPopulated = true + } + if _, isSet := params["scsi4"]; isSet { + disks.Disk_4 = QemuScsiStorage{}.mapToStruct(params["scsi4"].(string)) + structPopulated = true + } + if _, isSet := params["scsi5"]; isSet { + disks.Disk_5 = QemuScsiStorage{}.mapToStruct(params["scsi5"].(string)) + structPopulated = true + } + if _, isSet := params["scsi6"]; isSet { + disks.Disk_6 = QemuScsiStorage{}.mapToStruct(params["scsi6"].(string)) + structPopulated = true + } + if _, isSet := params["scsi7"]; isSet { + disks.Disk_7 = QemuScsiStorage{}.mapToStruct(params["scsi7"].(string)) + structPopulated = true + } + if _, isSet := params["scsi8"]; isSet { + disks.Disk_8 = QemuScsiStorage{}.mapToStruct(params["scsi8"].(string)) + structPopulated = true + } + if _, isSet := params["scsi9"]; isSet { + disks.Disk_9 = QemuScsiStorage{}.mapToStruct(params["scsi9"].(string)) + structPopulated = true + } + if _, isSet := params["scsi10"]; isSet { + disks.Disk_10 = QemuScsiStorage{}.mapToStruct(params["scsi10"].(string)) + structPopulated = true + } + if _, isSet := params["scsi11"]; isSet { + disks.Disk_11 = QemuScsiStorage{}.mapToStruct(params["scsi11"].(string)) + structPopulated = true + } + if _, isSet := params["scsi12"]; isSet { + disks.Disk_12 = QemuScsiStorage{}.mapToStruct(params["scsi12"].(string)) + structPopulated = true + } + if _, isSet := params["scsi13"]; isSet { + disks.Disk_13 = QemuScsiStorage{}.mapToStruct(params["scsi13"].(string)) + structPopulated = true + } + if _, isSet := params["scsi14"]; isSet { + disks.Disk_14 = QemuScsiStorage{}.mapToStruct(params["scsi14"].(string)) + structPopulated = true + } + if _, isSet := params["scsi15"]; isSet { + disks.Disk_15 = QemuScsiStorage{}.mapToStruct(params["scsi15"].(string)) + structPopulated = true + } + if _, isSet := params["scsi16"]; isSet { + disks.Disk_16 = QemuScsiStorage{}.mapToStruct(params["scsi16"].(string)) + structPopulated = true + } + if _, isSet := params["scsi17"]; isSet { + disks.Disk_17 = QemuScsiStorage{}.mapToStruct(params["scsi17"].(string)) + structPopulated = true + } + if _, isSet := params["scsi18"]; isSet { + disks.Disk_18 = QemuScsiStorage{}.mapToStruct(params["scsi18"].(string)) + structPopulated = true + } + if _, isSet := params["scsi19"]; isSet { + disks.Disk_19 = QemuScsiStorage{}.mapToStruct(params["scsi19"].(string)) + structPopulated = true + } + if _, isSet := params["scsi20"]; isSet { + disks.Disk_20 = QemuScsiStorage{}.mapToStruct(params["scsi20"].(string)) + structPopulated = true + } + if _, isSet := params["scsi21"]; isSet { + disks.Disk_21 = QemuScsiStorage{}.mapToStruct(params["scsi21"].(string)) + structPopulated = true + } + if _, isSet := params["scsi22"]; isSet { + disks.Disk_22 = QemuScsiStorage{}.mapToStruct(params["scsi22"].(string)) + structPopulated = true + } + if _, isSet := params["scsi23"]; isSet { + disks.Disk_23 = QemuScsiStorage{}.mapToStruct(params["scsi23"].(string)) + structPopulated = true + } + if _, isSet := params["scsi24"]; isSet { + disks.Disk_24 = QemuScsiStorage{}.mapToStruct(params["scsi24"].(string)) + structPopulated = true + } + if _, isSet := params["scsi25"]; isSet { + disks.Disk_25 = QemuScsiStorage{}.mapToStruct(params["scsi25"].(string)) + structPopulated = true + } + if _, isSet := params["scsi26"]; isSet { + disks.Disk_26 = QemuScsiStorage{}.mapToStruct(params["scsi26"].(string)) + structPopulated = true + } + if _, isSet := params["scsi27"]; isSet { + disks.Disk_27 = QemuScsiStorage{}.mapToStruct(params["scsi27"].(string)) + structPopulated = true + } + if _, isSet := params["scsi28"]; isSet { + disks.Disk_28 = QemuScsiStorage{}.mapToStruct(params["scsi28"].(string)) + structPopulated = true + } + if _, isSet := params["scsi29"]; isSet { + disks.Disk_29 = QemuScsiStorage{}.mapToStruct(params["scsi29"].(string)) + structPopulated = true + } + if _, isSet := params["scsi30"]; isSet { + disks.Disk_30 = QemuScsiStorage{}.mapToStruct(params["scsi30"].(string)) + structPopulated = true + } + if structPopulated { + return &disks + } + return nil +} + +type QemuScsiPassthrough struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + EmulateSSD bool + File string + IOThread bool + ReadOnly bool + Replicate bool + Size uint +} + +type QemuScsiStorage struct { + CdRom *QemuCdRom + CloudInit *QemuCloudInitDisk + Disk *QemuScsiDisk + Passthrough *QemuScsiPassthrough +} + +func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { + settings := splitStringOfSettings(param) + tmpCdRom := qemuCdRom{}.mapToStruct(settings) + if tmpCdRom != nil { + if tmpCdRom.FileType == "" { + return &QemuScsiStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} + } else { + return &QemuScsiStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} + } + } + + tmpDisk := qemuDisk{}.mapToStruct(settings) + if tmpDisk == nil { + return nil + } + if tmpDisk.File == "" { + return &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + }} + } + return &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Size: tmpDisk.Size, + }} + +} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go new file mode 100644 index 00000000..66f07dad --- /dev/null +++ b/proxmox/config_qemu_disk_virtio.go @@ -0,0 +1,165 @@ +package proxmox + +type QemuVirtIODisk struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + IOThread bool + ReadOnly bool + Size uint + Storage string +} + +type QemuVirtIODisks struct { + Disk_0 *QemuVirtIOStorage + Disk_1 *QemuVirtIOStorage + Disk_2 *QemuVirtIOStorage + Disk_3 *QemuVirtIOStorage + Disk_4 *QemuVirtIOStorage + Disk_5 *QemuVirtIOStorage + Disk_6 *QemuVirtIOStorage + Disk_7 *QemuVirtIOStorage + Disk_8 *QemuVirtIOStorage + Disk_9 *QemuVirtIOStorage + Disk_10 *QemuVirtIOStorage + Disk_11 *QemuVirtIOStorage + Disk_12 *QemuVirtIOStorage + Disk_13 *QemuVirtIOStorage + Disk_14 *QemuVirtIOStorage + Disk_15 *QemuVirtIOStorage +} + +func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODisks { + disks := QemuVirtIODisks{} + var structPopulated bool + if _, isSet := params["virtio0"]; isSet { + disks.Disk_0 = QemuVirtIOStorage{}.mapToStruct(params["virtio0"].(string)) + structPopulated = true + } + if _, isSet := params["virtio1"]; isSet { + disks.Disk_1 = QemuVirtIOStorage{}.mapToStruct(params["virtio1"].(string)) + structPopulated = true + } + if _, isSet := params["virtio2"]; isSet { + disks.Disk_2 = QemuVirtIOStorage{}.mapToStruct(params["virtio2"].(string)) + structPopulated = true + } + if _, isSet := params["virtio3"]; isSet { + disks.Disk_3 = QemuVirtIOStorage{}.mapToStruct(params["virtio3"].(string)) + structPopulated = true + } + if _, isSet := params["virtio4"]; isSet { + disks.Disk_4 = QemuVirtIOStorage{}.mapToStruct(params["virtio4"].(string)) + structPopulated = true + } + if _, isSet := params["virtio5"]; isSet { + disks.Disk_5 = QemuVirtIOStorage{}.mapToStruct(params["virtio5"].(string)) + structPopulated = true + } + if _, isSet := params["virtio6"]; isSet { + disks.Disk_6 = QemuVirtIOStorage{}.mapToStruct(params["virtio6"].(string)) + structPopulated = true + } + if _, isSet := params["virtio7"]; isSet { + disks.Disk_7 = QemuVirtIOStorage{}.mapToStruct(params["virtio7"].(string)) + structPopulated = true + } + if _, isSet := params["virtio8"]; isSet { + disks.Disk_8 = QemuVirtIOStorage{}.mapToStruct(params["virtio8"].(string)) + structPopulated = true + } + if _, isSet := params["virtio9"]; isSet { + disks.Disk_9 = QemuVirtIOStorage{}.mapToStruct(params["virtio9"].(string)) + structPopulated = true + } + if _, isSet := params["virtio10"]; isSet { + disks.Disk_10 = QemuVirtIOStorage{}.mapToStruct(params["virtio10"].(string)) + structPopulated = true + } + if _, isSet := params["virtio11"]; isSet { + disks.Disk_11 = QemuVirtIOStorage{}.mapToStruct(params["virtio11"].(string)) + structPopulated = true + } + if _, isSet := params["virtio12"]; isSet { + disks.Disk_12 = QemuVirtIOStorage{}.mapToStruct(params["virtio12"].(string)) + structPopulated = true + } + if _, isSet := params["virtio13"]; isSet { + disks.Disk_13 = QemuVirtIOStorage{}.mapToStruct(params["virtio13"].(string)) + structPopulated = true + } + if _, isSet := params["virtio14"]; isSet { + disks.Disk_14 = QemuVirtIOStorage{}.mapToStruct(params["virtio14"].(string)) + structPopulated = true + } + if _, isSet := params["virtio15"]; isSet { + disks.Disk_15 = QemuVirtIOStorage{}.mapToStruct(params["virtio15"].(string)) + structPopulated = true + } + if structPopulated { + return &disks + } + return nil +} + +type QemuVirtIOPassthrough struct { + AsyncIO QemuDiskAsyncIO + Backup bool + Bandwidth QemuDiskBandwidth + Cache QemuDiskCache + Discard bool + File string + IOThread bool + ReadOnly bool + Size uint +} + +type QemuVirtIOStorage struct { + CdRom *QemuCdRom + CloudInit *QemuCloudInitDisk + Disk *QemuVirtIODisk + Passthrough *QemuVirtIOPassthrough +} + +func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { + settings := splitStringOfSettings(param) + tmpCdRom := qemuCdRom{}.mapToStruct(settings) + if tmpCdRom != nil { + if tmpCdRom.FileType == "" { + return &QemuVirtIOStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} + } else { + return &QemuVirtIOStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} + } + } + + tmpDisk := qemuDisk{}.mapToStruct(settings) + if tmpDisk == nil { + return nil + } + if tmpDisk.File == "" { + return &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + }} + } + return &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + File: tmpDisk.File, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Size: tmpDisk.Size, + }} +} diff --git a/proxmox/util.go b/proxmox/util.go index 806f3a73..253fa4ea 100644 --- a/proxmox/util.go +++ b/proxmox/util.go @@ -204,3 +204,12 @@ func createHeaderList(header_string string, sess *Session) (*Session, error) { } return sess, nil } + +func splitStringOfSettings(settings string) (settingArray [][]string) { + settingValuePairs := strings.Split(settings, ",") + settingArray = make([][]string, len(settingValuePairs)) + for i, e := range settingValuePairs { + settingArray[i] = strings.SplitN(e, "=", 2) + } + return +} diff --git a/proxmox/util_test.go b/proxmox/util_test.go new file mode 100644 index 00000000..38b2c45a --- /dev/null +++ b/proxmox/util_test.go @@ -0,0 +1,28 @@ +package proxmox + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_splitStringOfSettings(t *testing.T) { + testData := []struct { + Input string + Output [][]string + }{ + { + Input: "setting=a,thing=b,randomString,doubleTest=value=equals,object=test", + Output: [][]string{ + {"setting", "a"}, + {"thing", "b"}, + {"randomString"}, + {"doubleTest", "value=equals"}, + {"object", "test"}, + }, + }, + } + for _, e := range testData { + require.Equal(t, e.Output, splitStringOfSettings(e.Input)) + } +} From a4ec1a168366171cfe2b9243c218044a7349af02 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 10:58:33 +0000 Subject: [PATCH 002/191] feat: Add Disks parameter in ConfigQemu struct --- proxmox/config_qemu.go | 80 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 1010a300..38efb72d 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -35,45 +35,46 @@ type AgentNetworkInterface struct { // ConfigQemu - Proxmox API QEMU options type ConfigQemu struct { - VmID int `json:"vmid,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - Pool string `json:"pool,omitempty"` - Bios string `json:"bios,omitempty"` - EFIDisk QemuDevice `json:"efidisk,omitempty"` - Machine string `json:"machine,omitempty"` - Onboot *bool `json:"onboot,omitempty"` - Startup string `json:"startup,omitempty"` - Tablet *bool `json:"tablet,omitempty"` - Agent int `json:"agent,omitempty"` - Memory int `json:"memory,omitempty"` - Balloon int `json:"balloon,omitempty"` - QemuOs string `json:"ostype,omitempty"` - QemuCores int `json:"cores,omitempty"` - QemuSockets int `json:"sockets,omitempty"` - QemuVcpus int `json:"vcpus,omitempty"` - QemuCpu string `json:"cpu,omitempty"` - QemuNuma *bool `json:"numa,omitempty"` - QemuKVM *bool `json:"kvm,omitempty"` - Hotplug string `json:"hotplug,omitempty"` - QemuIso string `json:"iso,omitempty"` - QemuPxe bool `json:"pxe,omitempty"` - FullClone *int `json:"fullclone,omitempty"` - Boot string `json:"boot,omitempty"` - BootDisk string `json:"bootdisk,omitempty"` - Scsihw string `json:"scsihw,omitempty"` - QemuDisks QemuDevices `json:"disk,omitempty"` - QemuUnusedDisks QemuDevices `json:"unused,omitempty"` - QemuVga QemuDevice `json:"vga,omitempty"` - QemuNetworks QemuDevices `json:"network,omitempty"` - QemuSerials QemuDevices `json:"serial,omitempty"` - QemuUsbs QemuDevices `json:"usb,omitempty"` - QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` - Hookscript string `json:"hookscript,omitempty"` - HaState string `json:"hastate,omitempty"` - HaGroup string `json:"hagroup,omitempty"` - Tags string `json:"tags,omitempty"` - Args string `json:"args,omitempty"` + VmID int `json:"vmid,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Pool string `json:"pool,omitempty"` + Bios string `json:"bios,omitempty"` + EFIDisk QemuDevice `json:"efidisk,omitempty"` + Machine string `json:"machine,omitempty"` + Onboot *bool `json:"onboot,omitempty"` + Startup string `json:"startup,omitempty"` + Tablet *bool `json:"tablet,omitempty"` + Agent int `json:"agent,omitempty"` + Memory int `json:"memory,omitempty"` + Balloon int `json:"balloon,omitempty"` + QemuOs string `json:"ostype,omitempty"` + QemuCores int `json:"cores,omitempty"` + QemuSockets int `json:"sockets,omitempty"` + QemuVcpus int `json:"vcpus,omitempty"` + QemuCpu string `json:"cpu,omitempty"` + QemuNuma *bool `json:"numa,omitempty"` + QemuKVM *bool `json:"kvm,omitempty"` + Hotplug string `json:"hotplug,omitempty"` + QemuIso string `json:"iso,omitempty"` + QemuPxe bool `json:"pxe,omitempty"` + FullClone *int `json:"fullclone,omitempty"` + Boot string `json:"boot,omitempty"` + BootDisk string `json:"bootdisk,omitempty"` + Scsihw string `json:"scsihw,omitempty"` + Disks *QemuStorages `json:"disks,omitempty"` + QemuDisks QemuDevices `json:"disk,omitempty"` + QemuUnusedDisks QemuDevices `json:"unused,omitempty"` + QemuVga QemuDevice `json:"vga,omitempty"` + QemuNetworks QemuDevices `json:"network,omitempty"` + QemuSerials QemuDevices `json:"serial,omitempty"` + QemuUsbs QemuDevices `json:"usb,omitempty"` + QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` + Hookscript string `json:"hookscript,omitempty"` + HaState string `json:"hastate,omitempty"` + HaGroup string `json:"hagroup,omitempty"` + Tags string `json:"tags,omitempty"` + Args string `json:"args,omitempty"` // cloud-init options CIuser string `json:"ciuser,omitempty"` @@ -127,6 +128,7 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { params["onboot"] = *config.Onboot } + // TODO conflicts with new mapping if config.QemuIso != "" { params["ide2"] = config.QemuIso + ",media=cdrom" } From 5fc83d2851fd8288fa60e2247f4d839b74cd1f4a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 11:05:39 +0000 Subject: [PATCH 003/191] feat: Map Qemu Disks to api values --- proxmox/config_qemu_disk.go | 147 +++++++++++++++++++++++---- proxmox/config_qemu_disk_ide.go | 85 ++++++++++++---- proxmox/config_qemu_disk_sata.go | 75 ++++++++++++-- proxmox/config_qemu_disk_scsi.go | 156 +++++++++++++++++++++++++++-- proxmox/config_qemu_disk_virtio.go | 107 ++++++++++++++++++-- 5 files changed, 503 insertions(+), 67 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 5e110e96..37be8dbc 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -1,6 +1,7 @@ package proxmox import ( + "fmt" "math" "strconv" "strings" @@ -19,6 +20,11 @@ type QemuCdRom struct { Passthrough bool } +// TODO write function +func (cdRom QemuCdRom) mapToApiValues() string { + return "" +} + func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { if !settings.Passthrough { return &QemuCdRom{ @@ -96,6 +102,11 @@ type QemuCloudInitDisk struct { FileType string } +// TODO write function +func (cloudInit QemuCloudInitDisk) mapToApiValues() string { + return "" +} + func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { return &QemuCloudInitDisk{ Storage: settings.Storage, @@ -129,32 +140,91 @@ type QemuDiskCache string // TODO add enum type QemuDiskFormat string -func (QemuDiskFormat) mapToStruct(setting string) QemuDiskFormat { - settings := strings.Split(setting, ".") - if len(settings) < 2 { - return "" - } - return QemuDiskFormat(settings[len(settings)-1]) -} - type qemuDisk struct { AsyncIO QemuDiskAsyncIO Backup bool Bandwidth QemuDiskBandwidth Cache QemuDiskCache Discard bool - EmulateSSD bool + EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type - // File is only set for Passthrough. - File string + File string // Only set for Passthrough. Format QemuDiskFormat - IOThread bool - ReadOnly bool + IOThread bool // Only set for scsi,virtio + Number uint // Only set for Disk + ReadOnly bool // Only set for scsi,virtio Replicate bool Size uint // TODO custom type - // Storage is only set for Disk - Storage string + Storage string // Only set for Disk + Type qemuDiskType +} + +func (disk qemuDisk) mapToApiValues(create bool) (settings string) { + if create { + if disk.Storage != "" { + settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) + } + } + + // Set File + + if disk.AsyncIO != "" { + settings = settings + ",aio=" + string(disk.AsyncIO) + } + if !disk.Backup { + settings = settings + ",backup=0" + } + if disk.Cache != "" { + settings = settings + ",cache=" + string(disk.Cache) + } + if disk.Discard { + settings = settings + ",discard=on" + } + // format + // media + + if disk.Bandwidth.ReadLimit_Iops.Concurrent >= 10 { + settings = settings + ",iops_rd=" + strconv.Itoa(int(disk.Bandwidth.ReadLimit_Iops.Concurrent)) + } + if disk.Bandwidth.ReadLimit_Iops.Burst >= 10 { + settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.ReadLimit_Iops.Burst)) + } + if disk.Bandwidth.WriteLimit_Iops.Concurrent >= 10 { + settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.WriteLimit_Iops.Concurrent)) + } + if disk.Bandwidth.WriteLimit_Iops.Burst >= 10 { + settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.WriteLimit_Iops.Burst)) + } + + if (disk.Type == scsi || disk.Type == virtIO) && disk.IOThread { + settings = settings + ",iothread=1" + } + + if disk.Bandwidth.ReadLimit_Data.Concurrent >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.ReadLimit_Data.Concurrent) + } + if disk.Bandwidth.ReadLimit_Data.Burst >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.ReadLimit_Data.Burst) + } + if disk.Bandwidth.WriteLimit_Data.Concurrent >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.WriteLimit_Data.Concurrent) + } + if disk.Bandwidth.WriteLimit_Data.Burst >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.WriteLimit_Data.Burst) + } + + if !disk.Replicate { + settings = settings + ",replicate=0" + } + if (disk.Type == scsi || disk.Type == virtIO) && disk.ReadOnly { + settings = settings + ",ro=1" + } + if disk.Type != virtIO && disk.EmulateSSD { + settings = settings + ",ssd=1" + } + + return } // Maps all the disk related settings @@ -168,8 +238,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { disk.File = settings[0][0] } else { // "test2:105/vm-105-disk-53.qcow2, - disk.Storage = strings.Split(settings[0][0], ":")[0] - disk.Format = QemuDiskFormat("").mapToStruct(settings[0][0]) + diskAndNumberAndFormat := strings.Split(settings[0][0], ":") + disk.Storage = diskAndNumberAndFormat[0] + if len(diskAndNumberAndFormat) == 2 { + numberAndFormat := strings.Split(diskAndNumberAndFormat[1], "-") + if len(numberAndFormat) == 2 { + tmp := strings.Split(numberAndFormat[1], ".") + tmpNumber, _ := strconv.Atoi(tmp[0]) + disk.Number = uint(tmpNumber) + if len(tmp) == 2 { + disk.Format = QemuDiskFormat(tmp[1]) + } + } + } } for _, e := range settings { @@ -245,11 +326,35 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { return &disk } +type qemuDiskType int + +const ( + ide qemuDiskType = 0 + sata qemuDiskType = 1 + scsi qemuDiskType = 2 + virtIO qemuDiskType = 3 +) + type QemuStorages struct { - Ide *QemuIdeDisks - Sata *QemuSataDisks - Scsi *QemuScsiDisks - VirtIO *QemuVirtIODisks + Ide *QemuIdeDisks `json:"ide,omitempty"` + Sata *QemuSataDisks `json:"sata,omitempty"` + Scsi *QemuScsiDisks `json:"scsi,omitempty"` + VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` +} + +func (storages QemuStorages) mapToApiValues(create bool, params map[string]interface{}) { + if storages.Ide != nil { + storages.Ide.mapToApiValues(create, params) + } + if storages.Sata != nil { + storages.Sata.mapToApiValues(create, params) + } + if storages.Scsi != nil { + storages.Scsi.mapToApiValues(create, params) + } + if storages.VirtIO != nil { + storages.VirtIO.mapToApiValues(create, params) + } } func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 9db3ba5b..69986585 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -1,22 +1,52 @@ package proxmox type QemuIdeDisk struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - Replicate bool - Size uint - Storage string + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard,omitempty"` + EmulateSSD bool `json:"emulatessd,omitempty"` + Replicate bool `json:"replicate,omitempty"` + Size uint `json:"size,omitempty"` + Storage string `json:"storage,omitempty"` +} + +func (disk QemuIdeDisk) mapToApiValues(create bool) string { + return qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + Replicate: disk.Replicate, + Size: disk.Size, + Storage: disk.Storage, + Type: ide, + }.mapToApiValues(create) } type QemuIdeDisks struct { - Disk_0 *QemuIdeStorage - Disk_1 *QemuIdeStorage - Disk_2 *QemuIdeStorage - Disk_3 *QemuIdeStorage + Disk_0 *QemuIdeStorage `json:"0,omitempty"` + Disk_1 *QemuIdeStorage `json:"1,omitempty"` + Disk_2 *QemuIdeStorage `json:"2,omitempty"` + Disk_3 *QemuIdeStorage `json:"3,omitempty"` +} + +func (disks QemuIdeDisks) mapToApiValues(create bool, params map[string]interface{}) { + if disks.Disk_0 != nil { + params["ide0"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_1 != nil { + params["ide1"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_2 != nil { + params["ide2"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_3 != nil { + params["ide3"] = disks.Disk_0.mapToApiValues(create) + } } func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { @@ -56,11 +86,32 @@ type QemuIdePassthrough struct { Size uint } +// TODO write function +func (passthrough QemuIdePassthrough) mapToApiValues() string { + return "" +} + type QemuIdeStorage struct { - CdRom *QemuCdRom - CloudInit *QemuCloudInitDisk - Disk *QemuIdeDisk - Passthrough *QemuIdePassthrough + CdRom *QemuCdRom `json:"cdrom,omitempty"` + CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` + Disk *QemuIdeDisk `json:"disk,omitempty"` + Passthrough *QemuIdePassthrough `json:"passthrough,omitempty"` +} + +func (storage QemuIdeStorage) mapToApiValues(create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(create) + } + if storage.CdRom != nil { + return storage.CdRom.mapToApiValues() + } + if storage.CloudInit != nil { + return storage.CloudInit.mapToApiValues() + } + if storage.Passthrough != nil { + return storage.Passthrough.mapToApiValues() + } + return "" } func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index ac1555c9..c1a447b3 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -1,15 +1,30 @@ package proxmox type QemuSataDisk struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - Replicate bool - Size uint - Storage string + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard,omitempty"` + EmulateSSD bool `json:"emulatessd,omitempty"` + Replicate bool `json:"replicate,omitempty"` + Size uint `json:"size,omitempty"` + Storage string `json:"storage,omitempty"` +} + +func (disk QemuSataDisk) mapToApiValues(create bool) string { + return qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + Replicate: disk.Replicate, + Size: disk.Size, + Storage: disk.Storage, + Type: sata, + }.mapToApiValues(create) } type QemuSataDisks struct { @@ -21,6 +36,27 @@ type QemuSataDisks struct { Disk_5 *QemuSataStorage } +func (disks QemuSataDisks) mapToApiValues(create bool, params map[string]interface{}) { + if disks.Disk_0 != nil { + params["sata0"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_1 != nil { + params["sata1"] = disks.Disk_1.mapToApiValues(create) + } + if disks.Disk_2 != nil { + params["sata2"] = disks.Disk_2.mapToApiValues(create) + } + if disks.Disk_3 != nil { + params["sata3"] = disks.Disk_3.mapToApiValues(create) + } + if disks.Disk_4 != nil { + params["sata4"] = disks.Disk_4.mapToApiValues(create) + } + if disks.Disk_5 != nil { + params["sata5"] = disks.Disk_5.mapToApiValues(create) + } +} + func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { disks := QemuSataDisks{} var structPopulated bool @@ -66,6 +102,11 @@ type QemuSataPassthrough struct { Size uint } +// TODO write function +func (passthrough QemuSataPassthrough) mapToApiValues() string { + return "" +} + type QemuSataStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -73,6 +114,22 @@ type QemuSataStorage struct { Passthrough *QemuSataPassthrough } +func (storage QemuSataStorage) mapToApiValues(create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(create) + } + if storage.CdRom != nil { + return storage.CdRom.mapToApiValues() + } + if storage.CloudInit != nil { + return storage.CloudInit.mapToApiValues() + } + if storage.Passthrough != nil { + return storage.Passthrough.mapToApiValues() + } + return "" +} + func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 5aa56e0b..de46ccce 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -1,17 +1,34 @@ package proxmox type QemuScsiDisk struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - IOThread bool - ReadOnly bool - Replicate bool - Size uint - Storage string + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard,omitempty"` + EmulateSSD bool `json:"emulatessd,omitempty"` + IOThread bool `json:"iothread,omitempty"` + ReadOnly bool `json:"readonly,omitempty"` + Replicate bool `json:"replicate,omitempty"` + Size uint `json:"size,omitempty"` + Storage string `json:"storage,omitempty"` +} + +func (disk QemuScsiDisk) mapToApiValues(create bool) string { + return qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + IOThread: disk.IOThread, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Size: disk.Size, + Storage: disk.Storage, + Type: scsi, + }.mapToApiValues(create) } type QemuScsiDisks struct { @@ -48,6 +65,102 @@ type QemuScsiDisks struct { Disk_30 *QemuScsiStorage } +func (disks QemuScsiDisks) mapToApiValues(create bool, params map[string]interface{}) { + if disks.Disk_0 != nil { + params["scsi0"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_1 != nil { + params["scsi1"] = disks.Disk_1.mapToApiValues(create) + } + if disks.Disk_2 != nil { + params["scsi2"] = disks.Disk_2.mapToApiValues(create) + } + if disks.Disk_3 != nil { + params["scsi3"] = disks.Disk_3.mapToApiValues(create) + } + if disks.Disk_4 != nil { + params["scsi4"] = disks.Disk_4.mapToApiValues(create) + } + if disks.Disk_5 != nil { + params["scsi5"] = disks.Disk_5.mapToApiValues(create) + } + if disks.Disk_6 != nil { + params["scsi6"] = disks.Disk_6.mapToApiValues(create) + } + if disks.Disk_7 != nil { + params["scsi7"] = disks.Disk_7.mapToApiValues(create) + } + if disks.Disk_8 != nil { + params["scsi8"] = disks.Disk_8.mapToApiValues(create) + } + if disks.Disk_9 != nil { + params["scsi9"] = disks.Disk_9.mapToApiValues(create) + } + if disks.Disk_10 != nil { + params["scsi10"] = disks.Disk_10.mapToApiValues(create) + } + if disks.Disk_11 != nil { + params["scsi11"] = disks.Disk_11.mapToApiValues(create) + } + if disks.Disk_12 != nil { + params["scsi12"] = disks.Disk_12.mapToApiValues(create) + } + if disks.Disk_13 != nil { + params["scsi13"] = disks.Disk_13.mapToApiValues(create) + } + if disks.Disk_14 != nil { + params["scsi14"] = disks.Disk_14.mapToApiValues(create) + } + if disks.Disk_15 != nil { + params["scsi15"] = disks.Disk_15.mapToApiValues(create) + } + if disks.Disk_16 != nil { + params["scsi16"] = disks.Disk_16.mapToApiValues(create) + } + if disks.Disk_17 != nil { + params["scsi17"] = disks.Disk_17.mapToApiValues(create) + } + if disks.Disk_18 != nil { + params["scsi18"] = disks.Disk_18.mapToApiValues(create) + } + if disks.Disk_19 != nil { + params["scsi19"] = disks.Disk_19.mapToApiValues(create) + } + if disks.Disk_20 != nil { + params["scsi20"] = disks.Disk_20.mapToApiValues(create) + } + if disks.Disk_21 != nil { + params["scsi21"] = disks.Disk_21.mapToApiValues(create) + } + if disks.Disk_22 != nil { + params["scsi22"] = disks.Disk_22.mapToApiValues(create) + } + if disks.Disk_23 != nil { + params["scsi23"] = disks.Disk_23.mapToApiValues(create) + } + if disks.Disk_24 != nil { + params["scsi24"] = disks.Disk_24.mapToApiValues(create) + } + if disks.Disk_25 != nil { + params["scsi25"] = disks.Disk_25.mapToApiValues(create) + } + if disks.Disk_26 != nil { + params["scsi26"] = disks.Disk_26.mapToApiValues(create) + } + if disks.Disk_27 != nil { + params["scsi27"] = disks.Disk_27.mapToApiValues(create) + } + if disks.Disk_28 != nil { + params["scsi28"] = disks.Disk_28.mapToApiValues(create) + } + if disks.Disk_29 != nil { + params["scsi29"] = disks.Disk_29.mapToApiValues(create) + } + if disks.Disk_30 != nil { + params["scsi30"] = disks.Disk_30.mapToApiValues(create) + } +} + func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { disks := QemuScsiDisks{} var structPopulated bool @@ -195,6 +308,11 @@ type QemuScsiPassthrough struct { Size uint } +// TODO write function +func (passthrough QemuScsiPassthrough) mapToApiValues() string { + return "" +} + type QemuScsiStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -202,6 +320,22 @@ type QemuScsiStorage struct { Passthrough *QemuScsiPassthrough } +func (storage QemuScsiStorage) mapToApiValues(create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(create) + } + if storage.CdRom != nil { + return storage.CdRom.mapToApiValues() + } + if storage.CloudInit != nil { + return storage.CloudInit.mapToApiValues() + } + if storage.Passthrough != nil { + return storage.Passthrough.mapToApiValues() + } + return "" +} + func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 66f07dad..f4f30e74 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -1,15 +1,31 @@ package proxmox type QemuVirtIODisk struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - IOThread bool - ReadOnly bool - Size uint - Storage string + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard,omitempty"` + IOThread bool `json:"iothread,omitempty"` + ReadOnly bool `json:"readonly,omitempty"` + Replicate bool `json:"replicate,omitempty"` + Size uint `json:"size,omitempty"` + Storage string `json:"storage,omitempty"` +} + +func (disk QemuVirtIODisk) mapToApiValues(create bool) string { + return qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + IOThread: disk.IOThread, + ReadOnly: disk.ReadOnly, + Size: disk.Size, + Storage: disk.Storage, + Type: virtIO, + }.mapToApiValues(create) } type QemuVirtIODisks struct { @@ -31,6 +47,57 @@ type QemuVirtIODisks struct { Disk_15 *QemuVirtIOStorage } +func (disks QemuVirtIODisks) mapToApiValues(create bool, params map[string]interface{}) { + if disks.Disk_0 != nil { + params["virtio0"] = disks.Disk_0.mapToApiValues(create) + } + if disks.Disk_1 != nil { + params["virtio1"] = disks.Disk_1.mapToApiValues(create) + } + if disks.Disk_2 != nil { + params["virtio2"] = disks.Disk_2.mapToApiValues(create) + } + if disks.Disk_3 != nil { + params["virtio3"] = disks.Disk_3.mapToApiValues(create) + } + if disks.Disk_4 != nil { + params["virtio4"] = disks.Disk_4.mapToApiValues(create) + } + if disks.Disk_5 != nil { + params["virtio5"] = disks.Disk_5.mapToApiValues(create) + } + if disks.Disk_6 != nil { + params["virtio6"] = disks.Disk_6.mapToApiValues(create) + } + if disks.Disk_7 != nil { + params["virtio7"] = disks.Disk_7.mapToApiValues(create) + } + if disks.Disk_8 != nil { + params["virtio8"] = disks.Disk_8.mapToApiValues(create) + } + if disks.Disk_9 != nil { + params["virtio9"] = disks.Disk_9.mapToApiValues(create) + } + if disks.Disk_10 != nil { + params["virtio10"] = disks.Disk_10.mapToApiValues(create) + } + if disks.Disk_11 != nil { + params["virtio11"] = disks.Disk_11.mapToApiValues(create) + } + if disks.Disk_12 != nil { + params["virtio12"] = disks.Disk_12.mapToApiValues(create) + } + if disks.Disk_13 != nil { + params["virtio13"] = disks.Disk_13.mapToApiValues(create) + } + if disks.Disk_14 != nil { + params["virtio14"] = disks.Disk_14.mapToApiValues(create) + } + if disks.Disk_15 != nil { + params["virtio15"] = disks.Disk_15.mapToApiValues(create) + } +} + func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODisks { disks := QemuVirtIODisks{} var structPopulated bool @@ -116,6 +183,11 @@ type QemuVirtIOPassthrough struct { Size uint } +// TODO write function +func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { + return "" +} + type QemuVirtIOStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -123,6 +195,22 @@ type QemuVirtIOStorage struct { Passthrough *QemuVirtIOPassthrough } +func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(create) + } + if storage.CdRom != nil { + return storage.CdRom.mapToApiValues() + } + if storage.CloudInit != nil { + return storage.CloudInit.mapToApiValues() + } + if storage.Passthrough != nil { + return storage.Passthrough.mapToApiValues() + } + return "" +} + func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) @@ -147,6 +235,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { Discard: tmpDisk.Discard, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, Size: tmpDisk.Size, Storage: tmpDisk.Storage, }} From a89a72e1db7f831e665220cea64d65a9122d093e Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 11:34:13 +0000 Subject: [PATCH 004/191] style: put in alphabetical order --- proxmox/config_qemu_disk.go | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 37be8dbc..79f9f8f6 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -114,32 +114,6 @@ func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { } } -// TODO add enum -type QemuDiskAsyncIO string - -type QemuDiskBandwidth struct { - ReadLimit_Data QemuDisk_Bandwidth_Data - WriteLimit_Data QemuDisk_Bandwidth_Data - ReadLimit_Iops QemuDisk_Bandwidth_Iops - WriteLimit_Iops QemuDisk_Bandwidth_Iops -} - -type QemuDisk_Bandwidth_Data struct { - Concurrent float32 - Burst float32 -} - -type QemuDisk_Bandwidth_Iops struct { - Concurrent uint - Burst uint -} - -// TODO add enum -type QemuDiskCache string - -// TODO add enum -type QemuDiskFormat string - type qemuDisk struct { AsyncIO QemuDiskAsyncIO Backup bool @@ -326,6 +300,32 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { return &disk } +// TODO add enum +type QemuDiskAsyncIO string + +type QemuDiskBandwidth struct { + ReadLimit_Data QemuDisk_Bandwidth_Data + WriteLimit_Data QemuDisk_Bandwidth_Data + ReadLimit_Iops QemuDisk_Bandwidth_Iops + WriteLimit_Iops QemuDisk_Bandwidth_Iops +} + +type QemuDisk_Bandwidth_Data struct { + Concurrent float32 + Burst float32 +} + +type QemuDisk_Bandwidth_Iops struct { + Concurrent uint + Burst uint +} + +// TODO add enum +type QemuDiskCache string + +// TODO add enum +type QemuDiskFormat string + type qemuDiskType int const ( From 8e45a16075ab16fcf174f025c27580917be7a30c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:23:59 +0000 Subject: [PATCH 005/191] feat: Add serial key to disks --- proxmox/config_qemu_disk.go | 26 ++++++++++++++++++++++++++ proxmox/config_qemu_disk_ide.go | 5 +++++ proxmox/config_qemu_disk_sata.go | 5 +++++ proxmox/config_qemu_disk_scsi.go | 5 +++++ proxmox/config_qemu_disk_virtio.go | 5 +++++ 5 files changed, 46 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 79f9f8f6..a8bb2642 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -1,8 +1,10 @@ package proxmox import ( + "errors" "fmt" "math" + "regexp" "strconv" "strings" ) @@ -128,6 +130,7 @@ type qemuDisk struct { Number uint // Only set for Disk ReadOnly bool // Only set for scsi,virtio Replicate bool + Serial QemuDiskSerial Size uint // TODO custom type Storage string // Only set for Disk @@ -194,6 +197,9 @@ func (disk qemuDisk) mapToApiValues(create bool) (settings string) { if (disk.Type == scsi || disk.Type == virtIO) && disk.ReadOnly { settings = settings + ",ro=1" } + if disk.Serial != "" { + settings = settings + ",serial=" + string(disk.Serial) + } if disk.Type != virtIO && disk.EmulateSSD { settings = settings + ",ssd=1" } @@ -288,6 +294,10 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { disk.ReadOnly, _ = strconv.ParseBool(e[1]) continue } + if e[0] == "serial" { + disk.Serial = QemuDiskSerial(e[1]) + continue + } if e[0] == "size" { diskSize, _ := strconv.Atoi(strings.TrimSuffix(e[1], "G")) disk.Size = uint(diskSize) @@ -326,6 +336,22 @@ type QemuDiskCache string // TODO add enum type QemuDiskFormat string +type QemuDiskSerial string + +// QemuDiskSerial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ +// And has a max length of 60 characters +// TODO create test +func (serial QemuDiskSerial) Validate() error { + regex, _ := regexp.Compile(`^([a-z]|[A-Z]|[0-9]|_|-)*$`) + if !regex.Match([]byte(serial)) { + return errors.New("serial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_") + } + if len(serial) > 60 { + return errors.New("serial may only be 60 characters long") + } + return nil +} + type qemuDiskType int const ( diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 69986585..f02bb471 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -8,6 +8,7 @@ type QemuIdeDisk struct { Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` Replicate bool `json:"replicate,omitempty"` + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` Storage string `json:"storage,omitempty"` } @@ -21,6 +22,7 @@ func (disk QemuIdeDisk) mapToApiValues(create bool) string { Discard: disk.Discard, EmulateSSD: disk.EmulateSSD, Replicate: disk.Replicate, + Serial: disk.Serial, Size: disk.Size, Storage: disk.Storage, Type: ide, @@ -83,6 +85,7 @@ type QemuIdePassthrough struct { EmulateSSD bool File string Replicate bool + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint } @@ -138,6 +141,7 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, Storage: tmpDisk.Storage, }} @@ -151,6 +155,7 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { EmulateSSD: tmpDisk.EmulateSSD, File: tmpDisk.File, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index c1a447b3..12134229 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -8,6 +8,7 @@ type QemuSataDisk struct { Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` Replicate bool `json:"replicate,omitempty"` + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` Storage string `json:"storage,omitempty"` } @@ -21,6 +22,7 @@ func (disk QemuSataDisk) mapToApiValues(create bool) string { Discard: disk.Discard, EmulateSSD: disk.EmulateSSD, Replicate: disk.Replicate, + Serial: disk.Serial, Size: disk.Size, Storage: disk.Storage, Type: sata, @@ -99,6 +101,7 @@ type QemuSataPassthrough struct { EmulateSSD bool File string Replicate bool + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint } @@ -154,6 +157,7 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, Storage: tmpDisk.Storage, }} @@ -167,6 +171,7 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { EmulateSSD: tmpDisk.EmulateSSD, File: tmpDisk.File, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index de46ccce..281558ce 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -10,6 +10,7 @@ type QemuScsiDisk struct { IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` Storage string `json:"storage,omitempty"` } @@ -25,6 +26,7 @@ func (disk QemuScsiDisk) mapToApiValues(create bool) string { IOThread: disk.IOThread, ReadOnly: disk.ReadOnly, Replicate: disk.Replicate, + Serial: disk.Serial, Size: disk.Size, Storage: disk.Storage, Type: scsi, @@ -305,6 +307,7 @@ type QemuScsiPassthrough struct { IOThread bool ReadOnly bool Replicate bool + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint } @@ -362,6 +365,7 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, Storage: tmpDisk.Storage, }} @@ -377,6 +381,7 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index f4f30e74..3ea6ed1b 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -9,6 +9,7 @@ type QemuVirtIODisk struct { IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` Storage string `json:"storage,omitempty"` } @@ -22,6 +23,7 @@ func (disk QemuVirtIODisk) mapToApiValues(create bool) string { Discard: disk.Discard, IOThread: disk.IOThread, ReadOnly: disk.ReadOnly, + Serial: disk.Serial, Size: disk.Size, Storage: disk.Storage, Type: virtIO, @@ -180,6 +182,7 @@ type QemuVirtIOPassthrough struct { File string IOThread bool ReadOnly bool + Serial QemuDiskSerial `json:"serial,omitempty"` Size uint } @@ -236,6 +239,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, Storage: tmpDisk.Storage, }} @@ -249,6 +253,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { File: tmpDisk.File, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, + Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} } From 4967e1bb6be59685a3e23fc4bcb0bc97a6b00644 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:25:02 +0000 Subject: [PATCH 006/191] docs: Add TODO --- proxmox/config_qemu_disk.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index a8bb2642..2b529eb1 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -137,6 +137,7 @@ type qemuDisk struct { Type qemuDiskType } +// TODO write test func (disk qemuDisk) mapToApiValues(create bool) (settings string) { if create { if disk.Storage != "" { @@ -208,6 +209,7 @@ func (disk qemuDisk) mapToApiValues(create bool) (settings string) { } // Maps all the disk related settings +// TODO write test func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(settings) == 0 { return nil From 7f697adb62c567dcd3edb15f23f7fbc697c16781 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 15:28:00 +0000 Subject: [PATCH 007/191] test: add test for QemuDiskSerial.Validate --- proxmox/config_qemu_disk.go | 1 - proxmox/config_qemu_disk_test.go | 24 ++++++ .../test_data_qemu/type_QemuDiskSerial.go | 80 +++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 proxmox/config_qemu_disk_test.go create mode 100644 test/data/test_data_qemu/type_QemuDiskSerial.go diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 2b529eb1..24b88cbd 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -342,7 +342,6 @@ type QemuDiskSerial string // QemuDiskSerial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ // And has a max length of 60 characters -// TODO create test func (serial QemuDiskSerial) Validate() error { regex, _ := regexp.Compile(`^([a-z]|[A-Z]|[0-9]|_|-)*$`) if !regex.Match([]byte(serial)) { diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go new file mode 100644 index 00000000..829b1b5c --- /dev/null +++ b/proxmox/config_qemu_disk_test.go @@ -0,0 +1,24 @@ +package proxmox + +import ( + "testing" + + "github.com/Telmate/proxmox-api-go/test/data/test_data_qemu" + "github.com/stretchr/testify/require" +) + +func Test_QemuDiskSerial_Validate(t *testing.T) { + testRunes := struct { + legal []string + illegal []string + }{ + legal: test_data_qemu.QemuDiskSerial_Legal(), + illegal: test_data_qemu.QemuDiskSerial_Illegal(), + } + for _, e := range testRunes.legal { + require.NoError(t, QemuDiskSerial(e).Validate()) + } + for _, e := range testRunes.illegal { + require.Error(t, QemuDiskSerial(e).Validate()) + } +} diff --git a/test/data/test_data_qemu/type_QemuDiskSerial.go b/test/data/test_data_qemu/type_QemuDiskSerial.go new file mode 100644 index 00000000..2bc96254 --- /dev/null +++ b/test/data/test_data_qemu/type_QemuDiskSerial.go @@ -0,0 +1,80 @@ +package test_data_qemu + +import "strings" + +// 60 valid charaters +func QemuDiskSerial_Max_Legal() string { + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678" +} + +// 61 valid charaters +func QemuDiskSerial_Max_Illegal() string { + return QemuDiskSerial_Max_Legal() + "A" +} + +// Has all the legal runes for the QemuDiskSerial type. +func QemuDiskSerial_Legal() []string { + legalRunes := strings.Split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_", "") + legalStrings := []string{ + "85__2-_2-p-d-___3GEEJ_6__--ccli_-_8--e-RJ3-_A_f_S_Z8-7Gga__5", + "___7_7-G-_rsMa_6---___a-TmE-H-AD_oV_K-0_9W_-y_4_k-_FU__fev-q", + "mU_a-8-_-3U--_D--o01_-T4E__4fsV-nX4kk_Nb-S_wYR7TktI-_vn1mcfR", + "5_GX4DevvIZ-_2-_u-_4_dKK19_P-K-kLpj-Hzw-b_12L20UU3--__Y_5_O-", + "h-m_B_J-mH_o3-r-JmE4-WqZ_tly--3aT-w_wznK_Q-0Hkk7W6b-Z____1IQ", + "-D-aS-dJSG_-s9_6_BWnt9z_6m_67oW__d4V8m-wb_6_8-_A--__-e--1X1-", + "0gLe0_P-r53-BfDk--1__23_-Zo0_V---f-__7_b52u6f72", + "dg-5d_Y1_v-7g-__I7__79_-j8-_-_", + "-7_G_-I-__a-w_-5GK-_9BMr-I_-_-f_7_-F-----6-FE-q7__0NJY-vL-e-", + "Xlgd__41_0E-S---1--_--_X1p8-_5YHt_1hO__2Op_73-5r-4", + "_0-Nn6__-u_07_A-1dqt-EG-_4-w90--A-ur_-3_", + "8_-xO-lN1_O_Q-4__-_7d-k-__s-p-_uQ2S_Ft_OR_-Ct_--Pb__U_U_g2t-", + "-q_-6h4--bbIl_A-xc_zl-v6Y-b-6__EG5_G__6_-q__pa5lAvq_F-Fhl-d3", + "53X-j50-ix--Iv_i", + "0_-7O6--51_4____-_-Zm4E__s-4_c_xN_Ik3_g-_t__-__C_---e-_--K_m", + "--_8__BvpmE6t-r_Ho_x-VZ_0___g__ui1v28ne--_-_k74_E3x_T_s--__B", + "__--9--c__7__9r-s-__yDTi-JSk-M_fH_-hGO9", + "_J-q_f_o_--l-MSe--9I_L_-lAs_-G-0--l-9_-6", + "--1tcB8J210JwYy22--c-_oXhHQ-Zyy--A1-dZ9394ieAaZrvC_U--KS2-r7", + "442_h_M-2-4G3K-_bN", + "b_NDX_3e6-k9_-HWZL_A5T_L-_-je66", + "__-_DfxD-9_l2_-n__Tn_-n_6aE_Bj_8chVS5p7Z_2812---h_4-_hsh-wAb", + "T08_-bRb-_zRKF1MPN6j7vyp0Pt_Q_x44__Y6_7_-XX-_-VqsRi_-0-s2-", + "Z___e_UT--G_9-9_E--__--ZT---1Leg__7-92_KErs-S-_t-K21_-OK_6Nx", + "-Plro-431-_", + "b__-_2_-u-K8--3-1-1", + "3_T40b6-Q__-Lz_3_4qN_", + "-p-_-T__MK-4D46-r7F_", + "Cn_f1-3J5T4x-g_-yoX3__0K_lV_W-glt-_eC_c_A_3l-m-_d_5_-5-iC___", + "-v7Y--G8T6-5k64-2-4kz-zqn70C__", + "7-7S70i_e-_a_8E---1X-_cW_--4z_8_4rm--6KCp_5_os8-_-4pvE_UC-_X", + "-mjp2--E8z-K-__2t", + "2b6-_-4jx6nM-Mm_-Sf_Wz-cv_---keD_6-_x_O0_D__d_Q-v04-h__x__6g", + "_-t0_Et_1_P0C5xSp_-3G2u68q4--YU7zQ_-_4-Y3OwT-8k-2F__Zf7_K78k", + "_R_-9-_5-K2R5zF_UJWfH_--_YQe8P4_nQ--JQ-Xu--lH-e_V0-c1_--e", + "J_y_-1X-_N84-Y-Ik6h-Y5Hz-_S__0-_-Y_V_-305-9i38TP_T--4y7Gb0g-", + "0Yl7_-Sn-_H__D_--_-_y-h-j1_-7mDVS9__R8Ty_-mwOJ-h__VmAy__q-_N", + "Yk-3Pt9VJqW-uu45w_f__a-TH_M_vkWq-O6__tk-P4-2-_CP-_7_owV_GyLZ", + "-3-M2362g3_9-___X404__0-E01TFHW3HV-1n_E_Ev_-_-E_-S----_F_k--", + "-0-5l1u_D_-Hyk_-_-s-3663_JE2-k", + "_-ML", + "75BHJ-tj-2Q-m-s4-f-y5-9L_-_dPC6A-_3y-3-Rp_-0V-3_I-6--_4THR2-", + "V__HM_guP-__ltfk___Et9V_v7U-83-TK15Xun", + "ax2_-7u_-GqG7d1BAe_4-dW3S0-1Vbj--_r_-63Hvn36P0---6N--e-_89_b", + "__-h_L-_3_Q__3czJ1_J_", + "-_-_-_9xGr-8207h9-4WerP5_-v0G_G9_-K9T8-gvQg-d__g____xf-F_---", + "M_6K2LVn--73f__-__A5V_t-l-_--5s92_u_f_n-R2Iy580M7J2vPe76GIt-", + "-f5oc-MG_GhR-8oxJ_---G____5--2-5___b-cTmfyO18-6Vip__-c_i5uV_", + "7-_17B__b113_9-cZ8S-", + "VvF1-MX6--Pj-M_-F_tU_6T-G___3U3-F4-5L__x-9uzgz_-_y4_-_-J--kE", + "", + QemuDiskSerial_Max_Legal(), + } + return append(legalRunes, legalStrings[:]...) +} + +// Has all the legal runes for the QemuDiskSerial type. +func QemuDiskSerial_Illegal() []string { + illegalRunes := strings.Split("`~!@#$%^&*()=+{}[]|\\;:'\"<,>.?/", "") + illegalSrings := []string{QemuDiskSerial_Max_Illegal()} + return append(illegalRunes, illegalSrings[:]...) +} From 4454dca2ba811e2fcadcea5a1017ee6a9d3b5a34 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:04:50 +0000 Subject: [PATCH 008/191] refactor: Add enum and validate allowed values --- proxmox/config_qemu_disk.go | 17 ++++++++++++++++- proxmox/config_qemu_disk_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 24b88cbd..f484aaa1 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -332,9 +332,24 @@ type QemuDisk_Bandwidth_Iops struct { Burst uint } -// TODO add enum type QemuDiskCache string +const ( + QemuDiskCache_None QemuDiskCache = "none" + QemuDiskCache_WriteThrough QemuDiskCache = "writethrough" + QemuDiskCache_WriteBack QemuDiskCache = "writeback" + QemuDiskCache_Unsafe QemuDiskCache = "unsafe" + QemuDiskCache_DirectSync QemuDiskCache = "directsync" +) + +func (cache QemuDiskCache) Validate() error { + switch cache { + case QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync: + return nil + } + return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s,", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) +} + // TODO add enum type QemuDiskFormat string diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 829b1b5c..e6fc3c03 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -7,6 +7,31 @@ import ( "github.com/stretchr/testify/require" ) +func Test_QemuDiskCache_Validate(t *testing.T) { + testData := []struct { + input QemuDiskCache + err bool + }{ + // Valid + {input: QemuDiskCache_None}, + {input: QemuDiskCache_WriteThrough}, + {input: QemuDiskCache_WriteBack}, + {input: QemuDiskCache_Unsafe}, + {input: QemuDiskCache_DirectSync}, + // Invalid + {input: "bla", err: true}, + {input: "invalid value", err: true}, + {input: "!@#$", err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskSerial_Validate(t *testing.T) { testRunes := struct { legal []string From 327c98ae91318d68f7a5ae750d6bca0814c9d564 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:51:21 +0000 Subject: [PATCH 009/191] fix: typo --- proxmox/config_qemu_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f484aaa1..3c093f16 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -347,7 +347,7 @@ func (cache QemuDiskCache) Validate() error { case QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync: return nil } - return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s,", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) + return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) } // TODO add enum From aec9e6d928f9435fad4e5efbc7d26d2ad0160481 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:58:34 +0000 Subject: [PATCH 010/191] feat: Add enum for QemuDiskFormat and validate allowed values --- proxmox/config_qemu_disk.go | 19 ++++++++++++++++++- proxmox/config_qemu_disk_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 3c093f16..83b45e1b 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -350,9 +350,26 @@ func (cache QemuDiskCache) Validate() error { return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) } -// TODO add enum type QemuDiskFormat string +const ( + QemuDiskFormat_Cow QemuDiskFormat = "cow" + QemuDiskFormat_Cloop QemuDiskFormat = "cloop" + QemuDiskFormat_Qcow QemuDiskFormat = "qcow" + QemuDiskFormat_Qcow2 QemuDiskFormat = "qcow2" + QemuDiskFormat_Qed QemuDiskFormat = "qed" + QemuDiskFormat_Vmdk QemuDiskFormat = "vmdk" + QemuDiskFormat_Raw QemuDiskFormat = "raw" +) + +func (format QemuDiskFormat) Validate() error { + switch format { + case QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: + return nil + } + return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) +} + type QemuDiskSerial string // QemuDiskSerial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index e6fc3c03..b10e6811 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -32,6 +32,33 @@ func Test_QemuDiskCache_Validate(t *testing.T) { } } +func Test_QemuDiskFormat_Validate(t *testing.T) { + testData := []struct { + input QemuDiskFormat + err bool + }{ + // Valid + {input: QemuDiskFormat_Cow}, + {input: QemuDiskFormat_Cloop}, + {input: QemuDiskFormat_Qcow}, + {input: QemuDiskFormat_Qcow2}, + {input: QemuDiskFormat_Qed}, + {input: QemuDiskFormat_Vmdk}, + {input: QemuDiskFormat_Raw}, + // Invalid + {input: "bla", err: true}, + {input: "invalid value", err: true}, + {input: "!@#$", err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskSerial_Validate(t *testing.T) { testRunes := struct { legal []string From 01714f439f30262febe1d76d4fb6087be7776801 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:05:49 +0000 Subject: [PATCH 011/191] feat: Add enum for QemuDiskAsyncIO and validate allowed values --- proxmox/config_qemu_disk.go | 15 ++++++++++++++- proxmox/config_qemu_disk_test.go | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 83b45e1b..a6f499c4 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -312,9 +312,22 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { return &disk } -// TODO add enum type QemuDiskAsyncIO string +const ( + QemuDiskAsyncIO_Native QemuDiskAsyncIO = "native" + QemuDiskAsyncIO_Threads QemuDiskAsyncIO = "threads" + QemuDiskAsyncIO_IOuring QemuDiskAsyncIO = "io_uring" +) + +func (asyncIO QemuDiskAsyncIO) Validate() error { + switch asyncIO { + case QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring: + return nil + } + return fmt.Errorf("asyncio can only be one of the following values: %s,%s,%s", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring) +} + type QemuDiskBandwidth struct { ReadLimit_Data QemuDisk_Bandwidth_Data WriteLimit_Data QemuDisk_Bandwidth_Data diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index b10e6811..25274d88 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -7,6 +7,29 @@ import ( "github.com/stretchr/testify/require" ) +func Test_QemuDiskAsyncIO_Validate(t *testing.T) { + testData := []struct { + input QemuDiskAsyncIO + err bool + }{ + // Valid + {input: QemuDiskAsyncIO_Native}, + {input: QemuDiskAsyncIO_Threads}, + {input: QemuDiskAsyncIO_IOuring}, + // Invalid + {input: "bla", err: true}, + {input: "invalid value", err: true}, + {input: "!@#$", err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskCache_Validate(t *testing.T) { testData := []struct { input QemuDiskCache From 79d897d2ad090c0eda0f4c337f76d0020de379a1 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:06:35 +0000 Subject: [PATCH 012/191] fix: change setting name in error message --- proxmox/config_qemu_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index a6f499c4..4ee0e749 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -380,7 +380,7 @@ func (format QemuDiskFormat) Validate() error { case QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: return nil } - return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) + return fmt.Errorf("format can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) } type QemuDiskSerial string From 02819355e94b6c868d17ef5216b11eb9cdb36a26 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:31:16 +0000 Subject: [PATCH 013/191] refactor: Add Json keys --- proxmox/config_qemu_disk_sata.go | 12 +++--- proxmox/config_qemu_disk_scsi.go | 62 +++++++++++++++--------------- proxmox/config_qemu_disk_virtio.go | 32 +++++++-------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 12134229..4033b00d 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -30,12 +30,12 @@ func (disk QemuSataDisk) mapToApiValues(create bool) string { } type QemuSataDisks struct { - Disk_0 *QemuSataStorage - Disk_1 *QemuSataStorage - Disk_2 *QemuSataStorage - Disk_3 *QemuSataStorage - Disk_4 *QemuSataStorage - Disk_5 *QemuSataStorage + Disk_0 *QemuSataStorage `json:"0,omitempty"` + Disk_1 *QemuSataStorage `json:"1,omitempty"` + Disk_2 *QemuSataStorage `json:"2,omitempty"` + Disk_3 *QemuSataStorage `json:"3,omitempty"` + Disk_4 *QemuSataStorage `json:"4,omitempty"` + Disk_5 *QemuSataStorage `json:"5,omitempty"` } func (disks QemuSataDisks) mapToApiValues(create bool, params map[string]interface{}) { diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 281558ce..b5db0189 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -34,37 +34,37 @@ func (disk QemuScsiDisk) mapToApiValues(create bool) string { } type QemuScsiDisks struct { - Disk_0 *QemuScsiStorage - Disk_1 *QemuScsiStorage - Disk_2 *QemuScsiStorage - Disk_3 *QemuScsiStorage - Disk_4 *QemuScsiStorage - Disk_5 *QemuScsiStorage - Disk_6 *QemuScsiStorage - Disk_7 *QemuScsiStorage - Disk_8 *QemuScsiStorage - Disk_9 *QemuScsiStorage - Disk_10 *QemuScsiStorage - Disk_11 *QemuScsiStorage - Disk_12 *QemuScsiStorage - Disk_13 *QemuScsiStorage - Disk_14 *QemuScsiStorage - Disk_15 *QemuScsiStorage - Disk_16 *QemuScsiStorage - Disk_17 *QemuScsiStorage - Disk_18 *QemuScsiStorage - Disk_19 *QemuScsiStorage - Disk_20 *QemuScsiStorage - Disk_21 *QemuScsiStorage - Disk_22 *QemuScsiStorage - Disk_23 *QemuScsiStorage - Disk_24 *QemuScsiStorage - Disk_25 *QemuScsiStorage - Disk_26 *QemuScsiStorage - Disk_27 *QemuScsiStorage - Disk_28 *QemuScsiStorage - Disk_29 *QemuScsiStorage - Disk_30 *QemuScsiStorage + Disk_0 *QemuScsiStorage `json:"0,omitempty"` + Disk_1 *QemuScsiStorage `json:"1,omitempty"` + Disk_2 *QemuScsiStorage `json:"2,omitempty"` + Disk_3 *QemuScsiStorage `json:"3,omitempty"` + Disk_4 *QemuScsiStorage `json:"4,omitempty"` + Disk_5 *QemuScsiStorage `json:"5,omitempty"` + Disk_6 *QemuScsiStorage `json:"6,omitempty"` + Disk_7 *QemuScsiStorage `json:"7,omitempty"` + Disk_8 *QemuScsiStorage `json:"8,omitempty"` + Disk_9 *QemuScsiStorage `json:"9,omitempty"` + Disk_10 *QemuScsiStorage `json:"10,omitempty"` + Disk_11 *QemuScsiStorage `json:"11,omitempty"` + Disk_12 *QemuScsiStorage `json:"12,omitempty"` + Disk_13 *QemuScsiStorage `json:"13,omitempty"` + Disk_14 *QemuScsiStorage `json:"14,omitempty"` + Disk_15 *QemuScsiStorage `json:"15,omitempty"` + Disk_16 *QemuScsiStorage `json:"16,omitempty"` + Disk_17 *QemuScsiStorage `json:"17,omitempty"` + Disk_18 *QemuScsiStorage `json:"18,omitempty"` + Disk_19 *QemuScsiStorage `json:"19,omitempty"` + Disk_20 *QemuScsiStorage `json:"20,omitempty"` + Disk_21 *QemuScsiStorage `json:"21,omitempty"` + Disk_22 *QemuScsiStorage `json:"22,omitempty"` + Disk_23 *QemuScsiStorage `json:"23,omitempty"` + Disk_24 *QemuScsiStorage `json:"24,omitempty"` + Disk_25 *QemuScsiStorage `json:"25,omitempty"` + Disk_26 *QemuScsiStorage `json:"26,omitempty"` + Disk_27 *QemuScsiStorage `json:"27,omitempty"` + Disk_28 *QemuScsiStorage `json:"28,omitempty"` + Disk_29 *QemuScsiStorage `json:"29,omitempty"` + Disk_30 *QemuScsiStorage `json:"30,omitempty"` } func (disks QemuScsiDisks) mapToApiValues(create bool, params map[string]interface{}) { diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 3ea6ed1b..3e60a558 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -31,22 +31,22 @@ func (disk QemuVirtIODisk) mapToApiValues(create bool) string { } type QemuVirtIODisks struct { - Disk_0 *QemuVirtIOStorage - Disk_1 *QemuVirtIOStorage - Disk_2 *QemuVirtIOStorage - Disk_3 *QemuVirtIOStorage - Disk_4 *QemuVirtIOStorage - Disk_5 *QemuVirtIOStorage - Disk_6 *QemuVirtIOStorage - Disk_7 *QemuVirtIOStorage - Disk_8 *QemuVirtIOStorage - Disk_9 *QemuVirtIOStorage - Disk_10 *QemuVirtIOStorage - Disk_11 *QemuVirtIOStorage - Disk_12 *QemuVirtIOStorage - Disk_13 *QemuVirtIOStorage - Disk_14 *QemuVirtIOStorage - Disk_15 *QemuVirtIOStorage + Disk_0 *QemuVirtIOStorage `json:"0,omitempty"` + Disk_1 *QemuVirtIOStorage `json:"1,omitempty"` + Disk_2 *QemuVirtIOStorage `json:"2,omitempty"` + Disk_3 *QemuVirtIOStorage `json:"3,omitempty"` + Disk_4 *QemuVirtIOStorage `json:"4,omitempty"` + Disk_5 *QemuVirtIOStorage `json:"5,omitempty"` + Disk_6 *QemuVirtIOStorage `json:"6,omitempty"` + Disk_7 *QemuVirtIOStorage `json:"7,omitempty"` + Disk_8 *QemuVirtIOStorage `json:"8,omitempty"` + Disk_9 *QemuVirtIOStorage `json:"9,omitempty"` + Disk_10 *QemuVirtIOStorage `json:"10,omitempty"` + Disk_11 *QemuVirtIOStorage `json:"11,omitempty"` + Disk_12 *QemuVirtIOStorage `json:"12,omitempty"` + Disk_13 *QemuVirtIOStorage `json:"13,omitempty"` + Disk_14 *QemuVirtIOStorage `json:"14,omitempty"` + Disk_15 *QemuVirtIOStorage `json:"15,omitempty"` } func (disks QemuVirtIODisks) mapToApiValues(create bool, params map[string]interface{}) { From aab856e3646b94359a26d438e480a4460ab6b6fe Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:34:34 +0000 Subject: [PATCH 014/191] feat: Map QemuCdRom to API values --- proxmox/config_qemu_disk.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 4ee0e749..7dafb33a 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -10,21 +10,27 @@ import ( ) type IsoFile struct { - Storage string - File string + Storage string `json:"storage"` + File string `json:"file"` // Size can only be retrieved, setting it has no effect - Size string + Size string `json:"size"` } type QemuCdRom struct { - Iso *IsoFile + Iso *IsoFile `json:"iso,omitempty"` // Passthrough and File are mutually exclusive - Passthrough bool + Passthrough bool `json:"passthrough,omitempty"` } -// TODO write function +// TODO write test func (cdRom QemuCdRom) mapToApiValues() string { - return "" + if cdRom.Passthrough { + return "cdrom,media=cdrom" + } + if cdRom.Iso != nil { + return cdRom.Iso.Storage + ":iso/" + cdRom.Iso.File + ",media=cdrom" + } + return "none,media=cdrom" } func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { From 13226066fa3d31a7d8184e917ffef775cd107819 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:55:54 +0000 Subject: [PATCH 015/191] feat: create logic for creating, updating, migrating and deleting disks --- proxmox/config_qemu_disk.go | 51 ++++++-- proxmox/config_qemu_disk_ide.go | 96 ++++++++++++-- proxmox/config_qemu_disk_sata.go | 104 ++++++++++++--- proxmox/config_qemu_disk_scsi.go | 204 ++++++++++++++++------------- proxmox/config_qemu_disk_virtio.go | 144 +++++++++++++------- 5 files changed, 413 insertions(+), 186 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 7dafb33a..3079ad02 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -132,8 +132,9 @@ type qemuDisk struct { // TODO custom type File string // Only set for Passthrough. Format QemuDiskFormat + ID uint // Only set for Disk IOThread bool // Only set for scsi,virtio - Number uint // Only set for Disk + Number uint ReadOnly bool // Only set for scsi,virtio Replicate bool Serial QemuDiskSerial @@ -229,11 +230,11 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { diskAndNumberAndFormat := strings.Split(settings[0][0], ":") disk.Storage = diskAndNumberAndFormat[0] if len(diskAndNumberAndFormat) == 2 { - numberAndFormat := strings.Split(diskAndNumberAndFormat[1], "-") - if len(numberAndFormat) == 2 { - tmp := strings.Split(numberAndFormat[1], ".") - tmpNumber, _ := strconv.Atoi(tmp[0]) - disk.Number = uint(tmpNumber) + idAndFormat := strings.Split(diskAndNumberAndFormat[1], "-") + if len(idAndFormat) == 2 { + tmp := strings.Split(idAndFormat[1], ".") + tmpId, _ := strconv.Atoi(tmp[0]) + disk.ID = uint(tmpId) if len(tmp) == 2 { disk.Format = QemuDiskFormat(tmp[1]) } @@ -404,6 +405,11 @@ func (serial QemuDiskSerial) Validate() error { return nil } +type qemuDiskShort struct { + Storage string + Id string +} + type qemuDiskType int const ( @@ -420,18 +426,35 @@ type QemuStorages struct { VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` } -func (storages QemuStorages) mapToApiValues(create bool, params map[string]interface{}) { +func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, params map[string]interface{}) *qemuUpdateChanges { + changes := &qemuUpdateChanges{} + if currentStorages.Ide != nil { + storages.Ide.mapToApiValues(currentStorages.Ide, params, changes) + } + if currentStorages.Sata != nil { + storages.Sata.mapToApiValues(currentStorages.Sata, params, changes) + } + if currentStorages.Scsi != nil { + storages.Scsi.mapToApiValues(currentStorages.Scsi, params, changes) + } + if currentStorages.VirtIO != nil { + storages.VirtIO.mapToApiValues(currentStorages.VirtIO, params, changes) + } + return changes +} + +func (storages QemuStorages) mapToApiValues(params map[string]interface{}) { if storages.Ide != nil { - storages.Ide.mapToApiValues(create, params) + storages.Ide.mapToApiValues(nil, params, nil) } if storages.Sata != nil { - storages.Sata.mapToApiValues(create, params) + storages.Sata.mapToApiValues(nil, params, nil) } if storages.Scsi != nil { - storages.Scsi.mapToApiValues(create, params) + storages.Scsi.mapToApiValues(nil, params, nil) } if storages.VirtIO != nil { - storages.VirtIO.mapToApiValues(create, params) + storages.VirtIO.mapToApiValues(nil, params, nil) } } @@ -447,3 +470,9 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { } return nil } + +type qemuUpdateChanges struct { + Move []qemuDiskShort + Delete []string + MigrationImpossible bool +} diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index f02bb471..d49d55ac 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -13,6 +13,7 @@ type QemuIdeDisk struct { Storage string `json:"storage,omitempty"` } +// TODO write test func (disk QemuIdeDisk) mapToApiValues(create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, @@ -36,21 +37,19 @@ type QemuIdeDisks struct { Disk_3 *QemuIdeStorage `json:"3,omitempty"` } -func (disks QemuIdeDisks) mapToApiValues(create bool, params map[string]interface{}) { - if disks.Disk_0 != nil { - params["ide0"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_1 != nil { - params["ide1"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_2 != nil { - params["ide2"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_3 != nil { - params["ide3"] = disks.Disk_0.mapToApiValues(create) - } +// TODO write test +func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, params map[string]interface{}, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuIdeDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "ide0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "ide1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "ide2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "ide3", params, changes) } +// TODO write test func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { disks := QemuIdeDisks{} var structPopulated bool @@ -90,6 +89,7 @@ type QemuIdePassthrough struct { } // TODO write function +// TODO write test func (passthrough QemuIdePassthrough) mapToApiValues() string { return "" } @@ -101,6 +101,7 @@ type QemuIdeStorage struct { Passthrough *QemuIdePassthrough `json:"passthrough,omitempty"` } +// TODO write test func (storage QemuIdeStorage) mapToApiValues(create bool) string { if storage.Disk != nil { return storage.Disk.mapToApiValues(create) @@ -117,6 +118,75 @@ func (storage QemuIdeStorage) mapToApiValues(create bool) string { return "" } +// TODO write test +func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + if storage == nil { + if currentStorage != nil { + changes.Delete = append(changes.Delete, id) + } + return + } + // CDROM + if storage.CdRom != nil { + // Create or Update + params[id] = storage.CdRom.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CdRom != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // CloudInit + if storage.CloudInit != nil { + // Create or Update + params[id] = storage.CloudInit.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CloudInit != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Disk + if storage.Disk != nil { + if currentStorage == nil || currentStorage.Disk == nil { + // Create + params[id] = storage.Disk.mapToApiValues(true) + } else { + if storage.Disk.Size >= currentStorage.Disk.Size { + // Update + if storage.Disk.Storage != currentStorage.Disk.Storage { + changes.Move = append(changes.Move, qemuDiskShort{ + Id: id, + Storage: storage.Disk.Storage, + }) + } + params[id] = storage.Disk.mapToApiValues(false) + } else { + // Delete and Create + changes.Delete = append(changes.Delete, id) + params[id] = storage.Disk.mapToApiValues(true) + } + } + return + } else if currentStorage != nil && currentStorage.Disk != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Passthrough + if storage.Passthrough != nil { + // Create or Update + changes.MigrationImpossible = true + params[id] = storage.Passthrough.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.Passthrough != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } +} + +// TODO write test func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 4033b00d..f39fd8b8 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -13,6 +13,7 @@ type QemuSataDisk struct { Storage string `json:"storage,omitempty"` } +// TODO write test func (disk QemuSataDisk) mapToApiValues(create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, @@ -38,27 +39,21 @@ type QemuSataDisks struct { Disk_5 *QemuSataStorage `json:"5,omitempty"` } -func (disks QemuSataDisks) mapToApiValues(create bool, params map[string]interface{}) { - if disks.Disk_0 != nil { - params["sata0"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_1 != nil { - params["sata1"] = disks.Disk_1.mapToApiValues(create) - } - if disks.Disk_2 != nil { - params["sata2"] = disks.Disk_2.mapToApiValues(create) - } - if disks.Disk_3 != nil { - params["sata3"] = disks.Disk_3.mapToApiValues(create) - } - if disks.Disk_4 != nil { - params["sata4"] = disks.Disk_4.mapToApiValues(create) - } - if disks.Disk_5 != nil { - params["sata5"] = disks.Disk_5.mapToApiValues(create) - } +// TODO write test +func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, params map[string]interface{}, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuSataDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "sata0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "sata1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "sata2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "sata3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "sata4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "sata5", params, changes) } +// TODO write test func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { disks := QemuSataDisks{} var structPopulated bool @@ -106,6 +101,7 @@ type QemuSataPassthrough struct { } // TODO write function +// TODO write test func (passthrough QemuSataPassthrough) mapToApiValues() string { return "" } @@ -117,6 +113,7 @@ type QemuSataStorage struct { Passthrough *QemuSataPassthrough } +// TODO write test func (storage QemuSataStorage) mapToApiValues(create bool) string { if storage.Disk != nil { return storage.Disk.mapToApiValues(create) @@ -133,6 +130,75 @@ func (storage QemuSataStorage) mapToApiValues(create bool) string { return "" } +// TODO write test +func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + if storage == nil { + if currentStorage != nil { + changes.Delete = append(changes.Delete, id) + } + return + } + // CDROM + if storage.CdRom != nil { + // Create or Update + params[id] = storage.CdRom.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CdRom != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // CloudInit + if storage.CloudInit != nil { + // Create or Update + params[id] = storage.CloudInit.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CloudInit != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Disk + if storage.Disk != nil { + if currentStorage == nil || currentStorage.Disk == nil { + // Create + params[id] = storage.Disk.mapToApiValues(true) + } else { + if storage.Disk.Size >= currentStorage.Disk.Size { + // Update + if storage.Disk.Storage != currentStorage.Disk.Storage { + changes.Move = append(changes.Move, qemuDiskShort{ + Id: id, + Storage: storage.Disk.Storage, + }) + } + params[id] = storage.Disk.mapToApiValues(false) + } else { + // Delete and Create + changes.Delete = append(changes.Delete, id) + params[id] = storage.Disk.mapToApiValues(true) + } + } + return + } else if currentStorage != nil && currentStorage.Disk != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Passthrough + if storage.Passthrough != nil { + // Create or Update + changes.MigrationImpossible = true + params[id] = storage.Passthrough.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.Passthrough != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } +} + +// TODO write test func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index b5db0189..b91f2eb3 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -15,6 +15,7 @@ type QemuScsiDisk struct { Storage string `json:"storage,omitempty"` } +// TODO write test func (disk QemuScsiDisk) mapToApiValues(create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, @@ -67,102 +68,46 @@ type QemuScsiDisks struct { Disk_30 *QemuScsiStorage `json:"30,omitempty"` } -func (disks QemuScsiDisks) mapToApiValues(create bool, params map[string]interface{}) { - if disks.Disk_0 != nil { - params["scsi0"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_1 != nil { - params["scsi1"] = disks.Disk_1.mapToApiValues(create) - } - if disks.Disk_2 != nil { - params["scsi2"] = disks.Disk_2.mapToApiValues(create) - } - if disks.Disk_3 != nil { - params["scsi3"] = disks.Disk_3.mapToApiValues(create) - } - if disks.Disk_4 != nil { - params["scsi4"] = disks.Disk_4.mapToApiValues(create) - } - if disks.Disk_5 != nil { - params["scsi5"] = disks.Disk_5.mapToApiValues(create) - } - if disks.Disk_6 != nil { - params["scsi6"] = disks.Disk_6.mapToApiValues(create) - } - if disks.Disk_7 != nil { - params["scsi7"] = disks.Disk_7.mapToApiValues(create) - } - if disks.Disk_8 != nil { - params["scsi8"] = disks.Disk_8.mapToApiValues(create) - } - if disks.Disk_9 != nil { - params["scsi9"] = disks.Disk_9.mapToApiValues(create) - } - if disks.Disk_10 != nil { - params["scsi10"] = disks.Disk_10.mapToApiValues(create) - } - if disks.Disk_11 != nil { - params["scsi11"] = disks.Disk_11.mapToApiValues(create) - } - if disks.Disk_12 != nil { - params["scsi12"] = disks.Disk_12.mapToApiValues(create) - } - if disks.Disk_13 != nil { - params["scsi13"] = disks.Disk_13.mapToApiValues(create) - } - if disks.Disk_14 != nil { - params["scsi14"] = disks.Disk_14.mapToApiValues(create) - } - if disks.Disk_15 != nil { - params["scsi15"] = disks.Disk_15.mapToApiValues(create) - } - if disks.Disk_16 != nil { - params["scsi16"] = disks.Disk_16.mapToApiValues(create) - } - if disks.Disk_17 != nil { - params["scsi17"] = disks.Disk_17.mapToApiValues(create) - } - if disks.Disk_18 != nil { - params["scsi18"] = disks.Disk_18.mapToApiValues(create) - } - if disks.Disk_19 != nil { - params["scsi19"] = disks.Disk_19.mapToApiValues(create) - } - if disks.Disk_20 != nil { - params["scsi20"] = disks.Disk_20.mapToApiValues(create) - } - if disks.Disk_21 != nil { - params["scsi21"] = disks.Disk_21.mapToApiValues(create) - } - if disks.Disk_22 != nil { - params["scsi22"] = disks.Disk_22.mapToApiValues(create) - } - if disks.Disk_23 != nil { - params["scsi23"] = disks.Disk_23.mapToApiValues(create) - } - if disks.Disk_24 != nil { - params["scsi24"] = disks.Disk_24.mapToApiValues(create) - } - if disks.Disk_25 != nil { - params["scsi25"] = disks.Disk_25.mapToApiValues(create) - } - if disks.Disk_26 != nil { - params["scsi26"] = disks.Disk_26.mapToApiValues(create) - } - if disks.Disk_27 != nil { - params["scsi27"] = disks.Disk_27.mapToApiValues(create) - } - if disks.Disk_28 != nil { - params["scsi28"] = disks.Disk_28.mapToApiValues(create) - } - if disks.Disk_29 != nil { - params["scsi29"] = disks.Disk_29.mapToApiValues(create) - } - if disks.Disk_30 != nil { - params["scsi30"] = disks.Disk_30.mapToApiValues(create) - } +// TODO write test +func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, params map[string]interface{}, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuScsiDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "scsi0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "scsi1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "scsi2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "scsi3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "scsi4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "scsi5", params, changes) + disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, "scsi6", params, changes) + disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, "scsi7", params, changes) + disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, "scsi8", params, changes) + disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, "scsi9", params, changes) + disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, "scsi10", params, changes) + disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, "scsi11", params, changes) + disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, "scsi12", params, changes) + disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, "scsi13", params, changes) + disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, "scsi14", params, changes) + disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, "scsi15", params, changes) + disks.Disk_16.markDiskChanges(tmpCurrentDisks.Disk_16, "scsi16", params, changes) + disks.Disk_17.markDiskChanges(tmpCurrentDisks.Disk_17, "scsi17", params, changes) + disks.Disk_18.markDiskChanges(tmpCurrentDisks.Disk_18, "scsi18", params, changes) + disks.Disk_19.markDiskChanges(tmpCurrentDisks.Disk_19, "scsi19", params, changes) + disks.Disk_20.markDiskChanges(tmpCurrentDisks.Disk_20, "scsi20", params, changes) + disks.Disk_21.markDiskChanges(tmpCurrentDisks.Disk_21, "scsi21", params, changes) + disks.Disk_22.markDiskChanges(tmpCurrentDisks.Disk_22, "scsi22", params, changes) + disks.Disk_23.markDiskChanges(tmpCurrentDisks.Disk_23, "scsi23", params, changes) + disks.Disk_24.markDiskChanges(tmpCurrentDisks.Disk_24, "scsi24", params, changes) + disks.Disk_25.markDiskChanges(tmpCurrentDisks.Disk_25, "scsi25", params, changes) + disks.Disk_26.markDiskChanges(tmpCurrentDisks.Disk_26, "scsi26", params, changes) + disks.Disk_27.markDiskChanges(tmpCurrentDisks.Disk_27, "scsi27", params, changes) + disks.Disk_28.markDiskChanges(tmpCurrentDisks.Disk_28, "scsi28", params, changes) + disks.Disk_29.markDiskChanges(tmpCurrentDisks.Disk_29, "scsi29", params, changes) + disks.Disk_30.markDiskChanges(tmpCurrentDisks.Disk_30, "scsi30", params, changes) } +// TODO write test func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { disks := QemuScsiDisks{} var structPopulated bool @@ -312,6 +257,7 @@ type QemuScsiPassthrough struct { } // TODO write function +// TODO write test func (passthrough QemuScsiPassthrough) mapToApiValues() string { return "" } @@ -323,6 +269,7 @@ type QemuScsiStorage struct { Passthrough *QemuScsiPassthrough } +// TODO write test func (storage QemuScsiStorage) mapToApiValues(create bool) string { if storage.Disk != nil { return storage.Disk.mapToApiValues(create) @@ -339,6 +286,75 @@ func (storage QemuScsiStorage) mapToApiValues(create bool) string { return "" } +// TODO write test +func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + if storage == nil { + if currentStorage != nil { + changes.Delete = append(changes.Delete, id) + } + return + } + // CDROM + if storage.CdRom != nil { + // Create or Update + params[id] = storage.CdRom.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CdRom != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // CloudInit + if storage.CloudInit != nil { + // Create or Update + params[id] = storage.CloudInit.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CloudInit != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Disk + if storage.Disk != nil { + if currentStorage == nil || currentStorage.Disk == nil { + // Create + params[id] = storage.Disk.mapToApiValues(true) + } else { + if storage.Disk.Size >= currentStorage.Disk.Size { + // Update + if storage.Disk.Storage != currentStorage.Disk.Storage { + changes.Move = append(changes.Move, qemuDiskShort{ + Id: id, + Storage: storage.Disk.Storage, + }) + } + params[id] = storage.Disk.mapToApiValues(false) + } else { + // Delete and Create + changes.Delete = append(changes.Delete, id) + params[id] = storage.Disk.mapToApiValues(true) + } + } + return + } else if currentStorage != nil && currentStorage.Disk != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Passthrough + if storage.Passthrough != nil { + // Create or Update + changes.MigrationImpossible = true + params[id] = storage.Passthrough.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.Passthrough != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } +} + +// TODO write test func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 3e60a558..a4590b8f 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -14,6 +14,7 @@ type QemuVirtIODisk struct { Storage string `json:"storage,omitempty"` } +// TODO write test func (disk QemuVirtIODisk) mapToApiValues(create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, @@ -49,57 +50,31 @@ type QemuVirtIODisks struct { Disk_15 *QemuVirtIOStorage `json:"15,omitempty"` } -func (disks QemuVirtIODisks) mapToApiValues(create bool, params map[string]interface{}) { - if disks.Disk_0 != nil { - params["virtio0"] = disks.Disk_0.mapToApiValues(create) - } - if disks.Disk_1 != nil { - params["virtio1"] = disks.Disk_1.mapToApiValues(create) - } - if disks.Disk_2 != nil { - params["virtio2"] = disks.Disk_2.mapToApiValues(create) - } - if disks.Disk_3 != nil { - params["virtio3"] = disks.Disk_3.mapToApiValues(create) - } - if disks.Disk_4 != nil { - params["virtio4"] = disks.Disk_4.mapToApiValues(create) - } - if disks.Disk_5 != nil { - params["virtio5"] = disks.Disk_5.mapToApiValues(create) - } - if disks.Disk_6 != nil { - params["virtio6"] = disks.Disk_6.mapToApiValues(create) - } - if disks.Disk_7 != nil { - params["virtio7"] = disks.Disk_7.mapToApiValues(create) - } - if disks.Disk_8 != nil { - params["virtio8"] = disks.Disk_8.mapToApiValues(create) - } - if disks.Disk_9 != nil { - params["virtio9"] = disks.Disk_9.mapToApiValues(create) - } - if disks.Disk_10 != nil { - params["virtio10"] = disks.Disk_10.mapToApiValues(create) - } - if disks.Disk_11 != nil { - params["virtio11"] = disks.Disk_11.mapToApiValues(create) - } - if disks.Disk_12 != nil { - params["virtio12"] = disks.Disk_12.mapToApiValues(create) - } - if disks.Disk_13 != nil { - params["virtio13"] = disks.Disk_13.mapToApiValues(create) - } - if disks.Disk_14 != nil { - params["virtio14"] = disks.Disk_14.mapToApiValues(create) - } - if disks.Disk_15 != nil { - params["virtio15"] = disks.Disk_15.mapToApiValues(create) - } +// TODO write test +func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, params map[string]interface{}, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuVirtIODisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "virtio0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "virtio1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "virtio2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "virtio3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "virtio4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "virtio5", params, changes) + disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, "virtio6", params, changes) + disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, "virtio7", params, changes) + disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, "virtio8", params, changes) + disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, "virtio9", params, changes) + disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, "virtio10", params, changes) + disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, "virtio11", params, changes) + disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, "virtio12", params, changes) + disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, "virtio13", params, changes) + disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, "virtio14", params, changes) + disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, "virtio15", params, changes) } +// TODO write test func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODisks { disks := QemuVirtIODisks{} var structPopulated bool @@ -187,6 +162,7 @@ type QemuVirtIOPassthrough struct { } // TODO write function +// TODO write test func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { return "" } @@ -198,6 +174,7 @@ type QemuVirtIOStorage struct { Passthrough *QemuVirtIOPassthrough } +// TODO write test func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { if storage.Disk != nil { return storage.Disk.mapToApiValues(create) @@ -214,6 +191,75 @@ func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { return "" } +// TODO write test +func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + if storage == nil { + if currentStorage != nil { + changes.Delete = append(changes.Delete, id) + } + return + } + // CDROM + if storage.CdRom != nil { + // Create or Update + params[id] = storage.CdRom.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CdRom != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // CloudInit + if storage.CloudInit != nil { + // Create or Update + params[id] = storage.CloudInit.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CloudInit != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Disk + if storage.Disk != nil { + if currentStorage == nil || currentStorage.Disk == nil { + // Create + params[id] = storage.Disk.mapToApiValues(true) + } else { + if storage.Disk.Size >= currentStorage.Disk.Size { + // Update + if storage.Disk.Storage != currentStorage.Disk.Storage { + changes.Move = append(changes.Move, qemuDiskShort{ + Id: id, + Storage: storage.Disk.Storage, + }) + } + params[id] = storage.Disk.mapToApiValues(false) + } else { + // Delete and Create + changes.Delete = append(changes.Delete, id) + params[id] = storage.Disk.mapToApiValues(true) + } + } + return + } else if currentStorage != nil && currentStorage.Disk != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } + // Passthrough + if storage.Passthrough != nil { + // Create or Update + changes.MigrationImpossible = true + params[id] = storage.Passthrough.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.Passthrough != nil { + // Delete + changes.Delete = append(changes.Delete, id) + return + } +} + +// TODO write test func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) From 9fce801b9f86343a1a98cf0c69607ecdb6430bad Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:23:44 +0000 Subject: [PATCH 016/191] refactor: remove errors that always return nil --- proxmox/config_qemu.go | 129 +++++++++-------------------------------- 1 file changed, 26 insertions(+), 103 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 38efb72d..143012ac 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -165,16 +165,10 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { } // Create disks config. - err = config.CreateQemuDisksParams(vmr.vmId, params, false) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuDisksParams(params, false) // Create EFI disk - err = config.CreateQemuEfiParams(params) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuEfiParams(params) // Create vga config. vgaParam := QemuDeviceParam{} @@ -184,33 +178,21 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { } // Create networks config. - err = config.CreateQemuNetworksParams(vmr.vmId, params) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuNetworksParams(vmr.vmId, params) // Create ipconfig. - err = config.CreateIpconfigParams(vmr.vmId, params) + err = config.CreateIpconfigParams(params) if err != nil { log.Printf("[ERROR] %q", err) } // Create serial interfaces - err = config.CreateQemuSerialsParams(vmr.vmId, params) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuSerialsParams(params) - err = config.CreateQemuPCIsParams(vmr.vmId, params) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuPCIsParams(params) // Create usb interfaces - err = config.CreateQemuUsbsParams(vmr.vmId, params) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuUsbsParams(params) exitStatus, err := client.CreateQemuVm(vmr.node, params) if err != nil { @@ -385,10 +367,7 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { "vmid": vmr.vmId, } // TODO keep going if error= - err = config.CreateQemuDisksParams(vmr.vmId, configParamsDisk, false) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuDisksParams(configParamsDisk, false) // TODO keep going if error= _, err = client.createVMDisks(vmr.node, configParamsDisk) if err != nil { @@ -403,10 +382,7 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { } // Create networks config. - err = config.CreateQemuNetworksParams(vmr.vmId, configParams) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuNetworksParams(vmr.vmId, configParams) // Create vga config. vgaParam := QemuDeviceParam{} @@ -415,21 +391,13 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { configParams["vga"] = strings.Join(vgaParam, ",") } // Create serial interfaces - err = config.CreateQemuSerialsParams(vmr.vmId, configParams) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuSerialsParams(configParams) // Create usb interfaces - err = config.CreateQemuUsbsParams(vmr.vmId, configParams) - if err != nil { - log.Printf("[ERROR] %q", err) - } + config.CreateQemuUsbsParams(configParams) + + config.CreateQemuPCIsParams(configParams) - err = config.CreateQemuPCIsParams(vmr.vmId, configParams) - if err != nil { - log.Printf("[ERROR] %q", err) - } // cloud-init options if config.CIuser != "" { configParams["ciuser"] = config.CIuser @@ -449,7 +417,7 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { if config.Sshkeys != "" { configParams["sshkeys"] = sshKeyUrlEncode(config.Sshkeys) } - err = config.CreateIpconfigParams(vmr.vmId, configParams) + err = config.CreateIpconfigParams(configParams) if err != nil { log.Printf("[ERROR] %q", err) } @@ -835,11 +803,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e vgaList := strings.Split(vga.(string), ",") vgaMap := QemuDevice{} - // TODO: keep going if error? - err = vgaMap.readDeviceConfig(vgaList) - if err != nil { - log.Printf("[ERROR] %q", err) - } + vgaMap.readDeviceConfig(vgaList) if len(vgaMap) > 0 { config.QemuVga = vgaMap } @@ -870,10 +834,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e } // Add rest of device config. - err = nicConfMap.readDeviceConfig(nicConfList[1:]) - if err != nil { - log.Printf("[ERROR] %q", err) - } + nicConfMap.readDeviceConfig(nicConfList[1:]) switch nicConfMap["firewall"] { case 1: nicConfMap["firewall"] = true @@ -938,10 +899,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e "host": host, } - err = usbConfMap.readDeviceConfig(usbConfList[1:]) - if err != nil { - log.Printf("[ERROR] %q", err) - } + usbConfMap.readDeviceConfig(usbConfList[1:]) if usbConfMap["usb3"] == 1 { usbConfMap["usb3"] = true } @@ -969,11 +927,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e hostPCIConfMap := QemuDevice{ "id": hostPCIID, } - err = hostPCIConfMap.readDeviceConfig(hostPCIConfList) - if err != nil { - log.Printf("[ERROR] %q", err) - } - + hostPCIConfMap.readDeviceConfig(hostPCIConfList) // And device config to usbs map. if len(hostPCIConfMap) > 0 { config.QemuPCIDevices[hostPCIID] = hostPCIConfMap @@ -989,7 +943,6 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e //log.Printf("[DEBUG] VM %d(%s) has no HA config", vmr.vmId, vmConfig["hostname"]) return config, nil } - return } @@ -1205,8 +1158,7 @@ func FormatUsbParam(usb QemuDevice) string { } // Create parameters for each Nic device. -func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interface{}) error { - +func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interface{}) { // For new style with multi net device. for nicID, nicConfMap := range c.QemuNetworks { @@ -1267,12 +1219,10 @@ func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interfa // Add nic to Qemu prams. params[qemuNicName] = strings.Join(nicConfParam, ",") } - - return nil } // Create parameters for each Cloud-Init ipconfig entry. -func (c ConfigQemu) CreateIpconfigParams(vmID int, params map[string]interface{}) error { +func (c ConfigQemu) CreateIpconfigParams(params map[string]interface{}) error { for ID, config := range c.Ipconfig { if ID > 15 { @@ -1289,9 +1239,7 @@ func (c ConfigQemu) CreateIpconfigParams(vmID int, params map[string]interface{} } // Create efi parameter. -func (c ConfigQemu) CreateQemuEfiParams( - params map[string]interface{}, -) error { +func (c ConfigQemu) CreateQemuEfiParams(params map[string]interface{}) { efiParam := QemuDeviceParam{} efiParam = efiParam.createDeviceParam(c.EFIDisk, nil) @@ -1312,16 +1260,10 @@ func (c ConfigQemu) CreateQemuEfiParams( } params["efidisk0"] = storage } - return nil } // Create parameters for each disk. -func (c ConfigQemu) CreateQemuDisksParams( - vmID int, - params map[string]interface{}, - cloned bool, -) error { - +func (c ConfigQemu) CreateQemuDisksParams(params map[string]interface{}, cloned bool) { // For new style with multi disk device. for diskID, diskConfMap := range c.QemuDisks { // skip the first disk for clones (may not always be right, but a template probably has at least 1 disk) @@ -1336,16 +1278,10 @@ func (c ConfigQemu) CreateQemuDisksParams( // Add back to Qemu prams. params[qemuDiskName] = FormatDiskParam(diskConfMap) } - - return nil } // Create parameters for each PCI Device -func (c ConfigQemu) CreateQemuPCIsParams( - vmID int, - params map[string]interface{}, -) error { - +func (c ConfigQemu) CreateQemuPCIsParams(params map[string]interface{}) { // For new style with multi pci device. for pciConfID, pciConfMap := range c.QemuPCIDevices { qemuPCIName := "hostpci" + strconv.Itoa(pciConfID) @@ -1360,15 +1296,10 @@ func (c ConfigQemu) CreateQemuPCIsParams( // Add back to Qemu prams. params[qemuPCIName] = strings.TrimSuffix(pcistring.String(), ",") } - return nil } // Create parameters for serial interface -func (c ConfigQemu) CreateQemuSerialsParams( - vmID int, - params map[string]interface{}, -) error { - +func (c ConfigQemu) CreateQemuSerialsParams(params map[string]interface{}) { // For new style with multi disk device. for serialID, serialConfMap := range c.QemuSerials { // Device name. @@ -1378,23 +1309,16 @@ func (c ConfigQemu) CreateQemuSerialsParams( // Add back to Qemu prams. params[qemuSerialName] = deviceType } - - return nil } // Create parameters for usb interface -func (c ConfigQemu) CreateQemuUsbsParams( - vmID int, - params map[string]interface{}, -) error { +func (c ConfigQemu) CreateQemuUsbsParams(params map[string]interface{}) { for usbID, usbConfMap := range c.QemuUsbs { qemuUsbName := "usb" + strconv.Itoa(usbID) // Add back to Qemu prams. params[qemuUsbName] = FormatUsbParam(usbConfMap) } - - return nil } // Create parameters for serial interface @@ -1437,13 +1361,12 @@ func (p QemuDeviceParam) createDeviceParam( } // readDeviceConfig - get standard sub-conf strings where `key=value` and update conf map. -func (confMap QemuDevice) readDeviceConfig(confList []string) error { +func (confMap QemuDevice) readDeviceConfig(confList []string) { // Add device config. for _, conf := range confList { key, value := ParseSubConf(conf, "=") confMap[key] = value } - return nil } func (c ConfigQemu) String() string { From 3f356ba1bd15872b3e86705275b9144aa67e7faa Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:30:46 +0000 Subject: [PATCH 017/191] docs: typos and capitalization --- proxmox/config_qemu.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 143012ac..ddb71df7 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -934,7 +934,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e } } - // hastate is return by the api for a vm resource type but not the hagroup + // HAstate is return by the api for a vm resource type but not the HAgroup err = client.ReadVMHA(vmr) if err == nil { config.HaState = vmr.HaState() @@ -1100,7 +1100,7 @@ func formatDeviceParam(device QemuDevice) string { return strings.Join(deviceConfParams, ",") } -// Given a QemuDevice (represesting a disk), return a param string to give to ProxMox +// Given a QemuDevice (representing a disk), return a param string to give to ProxMox func FormatDiskParam(disk QemuDevice) string { diskConfParam := QemuDeviceParam{} @@ -1148,7 +1148,7 @@ func FormatDiskParam(disk QemuDevice) string { return strings.Join(diskConfParam, ",") } -// Given a QemuDevice (represesting a usb), return a param string to give to ProxMox +// Given a QemuDevice (representing a usb), return a param string to give to ProxMox func FormatUsbParam(usb QemuDevice) string { usbConfParam := QemuDeviceParam{} @@ -1201,7 +1201,7 @@ func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interfa macAddr = nicConfMap["macaddr"].(string) } - // use model=mac format for older proxmox compatability as the parameters which will be sent to Proxmox API. + // use model=mac format for older proxmox compatibility as the parameters which will be sent to Proxmox API. nicConfParam = append(nicConfParam, fmt.Sprintf("%v=%v", nicConfMap["model"], macAddr)) // Set bridge if not nat. From 6671092226101f4804c6af9c27de15f11a335098 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:32:14 +0000 Subject: [PATCH 018/191] refactor: make variable camelCase --- proxmox/config_qemu.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index ddb71df7..6032577e 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -237,9 +237,9 @@ storage:xxx func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (err error) { vmr.SetVmType("qemu") var storage string - fullclone := "1" + fullClone := "1" if config.FullClone != nil { - fullclone = strconv.Itoa(*config.FullClone) + fullClone = strconv.Itoa(*config.FullClone) } if disk0Storage, ok := config.QemuDisks[0]["storage"].(string); ok && len(disk0Storage) > 0 { storage = disk0Storage @@ -248,13 +248,13 @@ func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) ( "newid": vmr.vmId, "target": vmr.node, "name": config.Name, - "full": fullclone, + "full": fullClone, } if vmr.pool != "" { params["pool"] = vmr.pool } - if fullclone == "1" && storage != "" { + if fullClone == "1" && storage != "" { params["storage"] = storage } From b9b36c1c23b93b3b8b9009381889fa1246283521 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:51:09 +0000 Subject: [PATCH 019/191] refactor: change array to string --- proxmox/config_qemu_disk.go | 2 +- proxmox/config_qemu_disk_ide.go | 12 ++++++------ proxmox/config_qemu_disk_sata.go | 12 ++++++------ proxmox/config_qemu_disk_scsi.go | 12 ++++++------ proxmox/config_qemu_disk_virtio.go | 12 ++++++------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 3079ad02..2d2a8746 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -473,6 +473,6 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { type qemuUpdateChanges struct { Move []qemuDiskShort - Delete []string + Delete string MigrationImpossible bool } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index d49d55ac..8e6d1a0d 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -122,7 +122,7 @@ func (storage QemuIdeStorage) mapToApiValues(create bool) string { func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { if currentStorage != nil { - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) } return } @@ -133,7 +133,7 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i return } else if currentStorage != nil && currentStorage.CdRom != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // CloudInit @@ -143,7 +143,7 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i return } else if currentStorage != nil && currentStorage.CloudInit != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Disk @@ -163,14 +163,14 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i params[id] = storage.Disk.mapToApiValues(false) } else { // Delete and Create - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) params[id] = storage.Disk.mapToApiValues(true) } } return } else if currentStorage != nil && currentStorage.Disk != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Passthrough @@ -181,7 +181,7 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i return } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index f39fd8b8..e1c1a614 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -134,7 +134,7 @@ func (storage QemuSataStorage) mapToApiValues(create bool) string { func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { if currentStorage != nil { - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) } return } @@ -145,7 +145,7 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, return } else if currentStorage != nil && currentStorage.CdRom != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // CloudInit @@ -155,7 +155,7 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, return } else if currentStorage != nil && currentStorage.CloudInit != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Disk @@ -175,14 +175,14 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, params[id] = storage.Disk.mapToApiValues(false) } else { // Delete and Create - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) params[id] = storage.Disk.mapToApiValues(true) } } return } else if currentStorage != nil && currentStorage.Disk != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Passthrough @@ -193,7 +193,7 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, return } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index b91f2eb3..51cb5129 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -290,7 +290,7 @@ func (storage QemuScsiStorage) mapToApiValues(create bool) string { func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { if currentStorage != nil { - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) } return } @@ -301,7 +301,7 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, return } else if currentStorage != nil && currentStorage.CdRom != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // CloudInit @@ -311,7 +311,7 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, return } else if currentStorage != nil && currentStorage.CloudInit != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Disk @@ -331,14 +331,14 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, params[id] = storage.Disk.mapToApiValues(false) } else { // Delete and Create - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) params[id] = storage.Disk.mapToApiValues(true) } } return } else if currentStorage != nil && currentStorage.Disk != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Passthrough @@ -349,7 +349,7 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, return } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index a4590b8f..151ae1a7 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -195,7 +195,7 @@ func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { if currentStorage != nil { - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) } return } @@ -206,7 +206,7 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor return } else if currentStorage != nil && currentStorage.CdRom != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // CloudInit @@ -216,7 +216,7 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor return } else if currentStorage != nil && currentStorage.CloudInit != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Disk @@ -236,14 +236,14 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor params[id] = storage.Disk.mapToApiValues(false) } else { // Delete and Create - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) params[id] = storage.Disk.mapToApiValues(true) } } return } else if currentStorage != nil && currentStorage.Disk != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } // Passthrough @@ -254,7 +254,7 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor return } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = append(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, id) return } } From f8864f33681bd227a594d328faa25e84fd9d5768 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:53:29 +0000 Subject: [PATCH 020/191] refactor: change mapping of qemu api parameters --- proxmox/config_qemu.go | 203 ++++++++++++++++++++++++++++------------- 1 file changed, 142 insertions(+), 61 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 6032577e..0ebd4080 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -89,64 +89,45 @@ type ConfigQemu struct { // CreateVm - Tell Proxmox API to make the VM func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { - if config.HasCloudInit() { - return fmt.Errorf("cloud-init parameters only supported on clones or updates") + params, _, err := config.mapToApiValues(ConfigQemu{}, vmr) + if err != nil { + return } - vmr.SetVmType("qemu") - params := map[string]interface{}{ - "vmid": vmr.vmId, - "name": config.Name, - "startup": config.Startup, - "agent": config.Agent, - "ostype": config.QemuOs, - "sockets": config.QemuSockets, - "cores": config.QemuCores, - "cpu": config.QemuCpu, - "hotplug": config.Hotplug, - "memory": config.Memory, - "boot": config.Boot, - "description": config.Description, - "tags": config.Tags, - "machine": config.Machine, - "args": config.Args, + exitStatus, err := client.CreateQemuVm(vmr.node, params) + if err != nil { + return fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) } - if config.QemuNuma != nil { - params["numa"] = *config.QemuNuma + _, err = client.UpdateVMHA(vmr, config.HaState, config.HaGroup) + if err != nil { + return fmt.Errorf("[ERROR] %q", err) } - if config.QemuKVM != nil { - params["kvm"] = *config.QemuKVM - } + return +} - if config.Tablet != nil { - params["tablet"] = *config.Tablet - } +func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { - if config.Onboot != nil { - params["onboot"] = *config.Onboot - } + vmr.SetVmType("qemu") - // TODO conflicts with new mapping - if config.QemuIso != "" { - params["ide2"] = config.QemuIso + ",media=cdrom" - } + var itemsToDelete string - if config.Bios != "" { - params["bios"] = config.Bios + params = map[string]interface{}{ + "vmid": vmr.vmId, } + if config.Args != "" { + params["args"] = config.Args + } + if config.Agent != 0 { + params["agent"] = config.Agent + } if config.Balloon >= 1 { params["balloon"] = config.Balloon } - - if config.QemuVcpus >= 1 { - params["vcpus"] = config.QemuVcpus - } - - if vmr.pool != "" { - params["pool"] = vmr.pool + if config.Bios != "" { + params["bios"] = config.Bios } if config.Boot != "" { params["boot"] = config.Boot @@ -154,56 +135,154 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { if config.BootDisk != "" { params["bootdisk"] = config.BootDisk } - + if config.CIcustom != "" { + params["cicustom"] = config.CIcustom + } + if config.CIpassword != "" { + params["cipassword"] = config.CIpassword + } + if config.CIuser != "" { + params["ciuser"] = config.CIuser + } + if config.QemuCores != 0 { + params["cores"] = config.QemuCores + } + if config.QemuCpu != "" { + params["cpu"] = config.QemuCpu + } + if config.Description != "" { + params["description"] = config.Description + } + if config.Hookscript != "" { + params["hookscript"] = config.Hookscript + } + if config.Hotplug != "" { + params["hotplug"] = config.Hotplug + } + if config.QemuKVM != nil { + params["kvm"] = *config.QemuKVM + } + if config.Machine != "" { + params["machine"] = config.Machine + } + if config.Memory != 0 { + params["memory"] = config.Memory + } + if config.Name != "" { + params["name"] = config.Name + } + if config.Nameserver != "" { + params["nameserver"] = config.Nameserver + } + if config.QemuNuma != nil { + params["numa"] = *config.QemuNuma + } + if config.Onboot != nil { + params["onboot"] = *config.Onboot + } + if config.QemuOs != "" { + params["ostype"] = config.QemuOs + } + if vmr.pool != "" { + params["pool"] = vmr.pool + } if config.Scsihw != "" { params["scsihw"] = config.Scsihw } - - err = config.CreateQemuMachineParam(params) - if err != nil { - log.Printf("[ERROR] %q", err) + if config.Searchdomain != "" { + params["searchdomain"] = config.Searchdomain + } + if config.QemuSockets != 0 { + params["sockets"] = config.QemuSockets + } + if config.Sshkeys != "" { + params["sshkeys"] = sshKeyUrlEncode(config.Sshkeys) + } + if config.Startup != "" { + params["startup"] = config.Startup + } + if config.Tablet != nil { + params["tablet"] = *config.Tablet + } + if config.Tags != "" { + params["tags"] = config.Tags + } + if config.QemuVcpus >= 1 { + params["vcpus"] = config.QemuVcpus } - // Create disks config. - config.CreateQemuDisksParams(params, false) + // Disks + if currentConfig.Disks != nil { + if config.Disks != nil { + markedDisks = config.Disks.markDiskChanges(*currentConfig.Disks, params) + } + if markedDisks.Delete != "" { + itemsToDelete = AddToList(itemsToDelete, markedDisks.Delete) + } + } else { + if config.Disks != nil { + config.Disks.mapToApiValues(params) + } + } // Create EFI disk config.CreateQemuEfiParams(params) + // Create networks config. + config.CreateQemuNetworksParams(vmr.vmId, params) + // Create vga config. vgaParam := QemuDeviceParam{} vgaParam = vgaParam.createDeviceParam(config.QemuVga, nil) if len(vgaParam) > 0 { params["vga"] = strings.Join(vgaParam, ",") } + // Create serial interfaces + config.CreateQemuSerialsParams(params) - // Create networks config. - config.CreateQemuNetworksParams(vmr.vmId, params) + // Create usb interfaces + config.CreateQemuUsbsParams(params) + + config.CreateQemuPCIsParams(params) - // Create ipconfig. err = config.CreateIpconfigParams(params) if err != nil { log.Printf("[ERROR] %q", err) } - // Create serial interfaces - config.CreateQemuSerialsParams(params) + if itemsToDelete != "" { + params["delete"] = itemsToDelete + } + return +} - config.CreateQemuPCIsParams(params) +func (newConfig ConfigQemu) Update(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { + params, markedDisks, err := newConfig.mapToApiValues(*currentConfig, vmr) + if err != nil { + return + } - // Create usb interfaces - config.CreateQemuUsbsParams(params) + for _, e := range markedDisks.Move { + _, err = client.MoveQemuDisk(vmr, e.Id, e.Storage) + if err != nil { + return + } + } - exitStatus, err := client.CreateQemuVm(vmr.node, params) + // TODO Migrate VM + + _, err = client.SetVmConfig(vmr, params) if err != nil { - return fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) + log.Print(err) + return err } - _, err = client.UpdateVMHA(vmr, config.HaState, config.HaGroup) + _, err = client.UpdateVMHA(vmr, newConfig.HaState, newConfig.HaGroup) if err != nil { log.Printf("[ERROR] %q", err) } + _, err = client.UpdateVMPool(vmr, newConfig.Pool) return } @@ -680,6 +759,8 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e config.Ipconfig[ipconfigID] = ipConfStr } + config.Disks = QemuStorages{}.mapToStruct(vmConfig) + // Add disks. diskNames := []string{} From a2bb827e66e620972471c8cc593910a3cf7d9d42 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:56:18 +0000 Subject: [PATCH 021/191] mark `ConfigQemu.QemuDisks` as Deprecated --- proxmox/config_qemu.go | 85 +----------------------------------------- 1 file changed, 1 insertion(+), 84 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 0ebd4080..f27856ff 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -63,7 +63,7 @@ type ConfigQemu struct { BootDisk string `json:"bootdisk,omitempty"` Scsihw string `json:"scsihw,omitempty"` Disks *QemuStorages `json:"disks,omitempty"` - QemuDisks QemuDevices `json:"disk,omitempty"` + QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead QemuUnusedDisks QemuDevices `json:"unused,omitempty"` QemuVga QemuDevice `json:"vga,omitempty"` QemuNetworks QemuDevices `json:"network,omitempty"` @@ -761,89 +761,6 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e config.Disks = QemuStorages{}.mapToStruct(vmConfig) - // Add disks. - diskNames := []string{} - - for k := range vmConfig { - if diskName := rxDiskName.FindStringSubmatch(k); len(diskName) > 0 { - diskNames = append(diskNames, diskName[0]) - } - } - - for _, diskName := range diskNames { - var isDiskByID bool = false - diskConfStr := vmConfig[diskName].(string) - - id := rxDeviceID.FindStringSubmatch(diskName) - diskID, _ := strconv.Atoi(id[0]) - diskType := rxDiskType.FindStringSubmatch(diskName)[0] - - diskConfMap := ParsePMConf(diskConfStr, "volume") - diskByID := rxDiskPath.FindStringSubmatch(diskConfMap["volume"].(string)) - if len(diskByID) > 0 && diskByID[0] != "" { - isDiskByID = true - } - - if diskConfMap["volume"].(string) == "none" { - continue - } - - diskConfMap["slot"] = diskID - diskConfMap["type"] = diskType - - storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") - diskConfMap["storage"] = storageName - diskConfMap["file"] = fileName - - filePath := diskConfMap["volume"] - - // Get disk format - storageContent, err := client.GetStorageContent(vmr, storageName) - if err != nil { - log.Fatal(err) - return nil, err - } - var storageFormat string - contents := storageContent["data"].([]interface{}) - for content := range contents { - storageContentMap := contents[content].(map[string]interface{}) - if storageContentMap["volid"] == filePath { - storageFormat = storageContentMap["format"].(string) - break - } - } - diskConfMap["format"] = storageFormat - - // Get storage type for disk - var storageStatus map[string]interface{} - if !isDiskByID { - storageStatus, err = client.GetStorageStatus(vmr, storageName) - if err != nil { - log.Fatal(err) - return nil, err - } - storageType := storageStatus["type"] - - diskConfMap["storage_type"] = storageType - } - // cloud-init disks not always have the size sent by the API, which results in a crash - if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { - diskConfMap["size"] = "4M" // default cloud-init disk size - } - - var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) - // Convert to gigabytes if disk size was received in terabytes - matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) - if matched { - diskConfMap["size"] = fmt.Sprintf("%.0fG", DiskSizeGB(diskConfMap["size"])) - } - - // And device config to disks map. - if len(diskConfMap) > 0 { - config.QemuDisks[diskID] = diskConfMap - } - } - // Add unused disks // unused0:local:100/vm-100-disk-1.qcow2 unusedDiskNames := []string{} From 967e9fdf70ac555f13a769aa4f8f40f6acde860f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:58:14 +0000 Subject: [PATCH 022/191] Make `ConfigQemu.BootDisk` read only --- proxmox/config_qemu.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index f27856ff..0bf71dc3 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -60,7 +60,7 @@ type ConfigQemu struct { QemuPxe bool `json:"pxe,omitempty"` FullClone *int `json:"fullclone,omitempty"` Boot string `json:"boot,omitempty"` - BootDisk string `json:"bootdisk,omitempty"` + BootDisk string `json:"bootdisk,omitempty"` // Only returned as it's deprecated in the proxmox api Scsihw string `json:"scsihw,omitempty"` Disks *QemuStorages `json:"disks,omitempty"` QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead @@ -132,9 +132,6 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (p if config.Boot != "" { params["boot"] = config.Boot } - if config.BootDisk != "" { - params["bootdisk"] = config.BootDisk - } if config.CIcustom != "" { params["cicustom"] = config.CIcustom } From 50637760aae56452ee7c7310863a22b592fc6319 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 18:06:13 +0000 Subject: [PATCH 023/191] Mark func as Deprecated --- proxmox/config_qemu.go | 1 + 1 file changed, 1 insertion(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 0bf71dc3..a72cd1f2 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -338,6 +338,7 @@ func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) ( return err } +// DEPRECATED use ConfigQemu.Update instead func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { configParams := map[string]interface{}{} From 214163e7dac62afb73d2bdafcbb64858c913aa12 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 18:22:34 +0000 Subject: [PATCH 024/191] Mark func as Deprecated --- proxmox/client.go | 2 +- proxmox/config_qemu.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index e0ae4985..b2079ccd 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -696,7 +696,7 @@ func (c *Client) RollbackQemuVm(vmr *VmRef, snapshot string) (exitStatus string, return RollbackSnapshot(c, vmr, snapshot) } -// SetVmConfig - send config options +// DEPRECATED SetVmConfig - send config options func (c *Client) SetVmConfig(vmr *VmRef, params map[string]interface{}) (exitStatus interface{}, err error) { return c.PostWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") } diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index a72cd1f2..bd09cc08 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -268,10 +268,9 @@ func (newConfig ConfigQemu) Update(currentConfig *ConfigQemu, vmr *VmRef, client // TODO Migrate VM - _, err = client.SetVmConfig(vmr, params) + _, err = client.PostWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") if err != nil { - log.Print(err) - return err + return } _, err = client.UpdateVMHA(vmr, newConfig.HaState, newConfig.HaGroup) From 8ec657cbfba60950547d82fd3c57d4957e817595 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 18:24:47 +0000 Subject: [PATCH 025/191] fix: return error instead of printing it --- proxmox/config_qemu.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index bd09cc08..9c785a89 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -275,7 +275,7 @@ func (newConfig ConfigQemu) Update(currentConfig *ConfigQemu, vmr *VmRef, client _, err = client.UpdateVMHA(vmr, newConfig.HaState, newConfig.HaGroup) if err != nil { - log.Printf("[ERROR] %q", err) + return } _, err = client.UpdateVMPool(vmr, newConfig.Pool) From 7113ce24ebf5c7b1eda6afdb7aeaa847ab1b45ec Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:06:16 +0000 Subject: [PATCH 026/191] feat: added `UpdateAdvanced` and `Update` this allows for the user to manually provide the current config or let the library provide the config --- proxmox/config_qemu.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 9c785a89..88b6158e 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -253,7 +253,15 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (p return } -func (newConfig ConfigQemu) Update(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { +func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { + currentConfig, err := NewConfigQemuFromApi(vmr, client) + if err != nil { + return + } + return newConfig.UpdateAdvanced(currentConfig, vmr, client) +} + +func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { params, markedDisks, err := newConfig.mapToApiValues(*currentConfig, vmr) if err != nil { return From 1cc8b061254c358f3bd11577079d574eb7c6ed54 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 10 Mar 2023 09:29:14 +0000 Subject: [PATCH 027/191] feat: Map passthrough disk to api --- proxmox/config_qemu_disk.go | 3 +++ proxmox/config_qemu_disk_ide.go | 15 +++++++++++++-- proxmox/config_qemu_disk_sata.go | 15 +++++++++++++-- proxmox/config_qemu_disk_scsi.go | 17 +++++++++++++++-- proxmox/config_qemu_disk_virtio.go | 15 +++++++++++++-- 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 2d2a8746..b79cd252 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -152,6 +152,9 @@ func (disk qemuDisk) mapToApiValues(create bool) (settings string) { } } + if disk.File != "" { + settings = disk.File + } // Set File if disk.AsyncIO != "" { diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 8e6d1a0d..dda47127 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -88,10 +88,21 @@ type QemuIdePassthrough struct { Size uint } -// TODO write function // TODO write test func (passthrough QemuIdePassthrough) mapToApiValues() string { - return "" + return qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Size: passthrough.Size, + Type: ide, + }.mapToApiValues(false) } type QemuIdeStorage struct { diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index e1c1a614..e28d7459 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -100,10 +100,21 @@ type QemuSataPassthrough struct { Size uint } -// TODO write function // TODO write test func (passthrough QemuSataPassthrough) mapToApiValues() string { - return "" + return qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Size: passthrough.Size, + Type: sata, + }.mapToApiValues(false) } type QemuSataStorage struct { diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 51cb5129..28d48598 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -256,10 +256,23 @@ type QemuScsiPassthrough struct { Size uint } -// TODO write function // TODO write test func (passthrough QemuScsiPassthrough) mapToApiValues() string { - return "" + return qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Size: passthrough.Size, + Type: scsi, + }.mapToApiValues(false) } type QemuScsiStorage struct { diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 151ae1a7..c448df05 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -161,10 +161,21 @@ type QemuVirtIOPassthrough struct { Size uint } -// TODO write function // TODO write test func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { - return "" + return qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Serial: passthrough.Serial, + Size: passthrough.Size, + Type: scsi, + }.mapToApiValues(false) } type QemuVirtIOStorage struct { From 5644d23a3f5a56d26c048716d2aa2ca15f16318d Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 10 Mar 2023 09:31:44 +0000 Subject: [PATCH 028/191] feat: map cloud-init disk to api --- proxmox/config_qemu_disk.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index b79cd252..0d4a8d4a 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -110,9 +110,9 @@ type QemuCloudInitDisk struct { FileType string } -// TODO write function +// TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { - return "" + return cloudInit.Storage + ":cloudinit,format=" + cloudInit.FileType } func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { From 4e7d7be8b35a69d0a75ba6ca5061272e8ff2389e Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 10 Mar 2023 09:38:35 +0000 Subject: [PATCH 029/191] refactor: change logic for when a disk needs to be deleted --- proxmox/config_qemu_disk.go | 5 ++--- proxmox/config_qemu_disk_ide.go | 8 ++++---- proxmox/config_qemu_disk_sata.go | 8 ++++---- proxmox/config_qemu_disk_scsi.go | 8 ++++---- proxmox/config_qemu_disk_virtio.go | 8 ++++---- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 0d4a8d4a..055200ca 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -475,7 +475,6 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { } type qemuUpdateChanges struct { - Move []qemuDiskShort - Delete string - MigrationImpossible bool + Move []qemuDiskShort + Delete string } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index dda47127..5445f090 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -132,9 +132,6 @@ func (storage QemuIdeStorage) mapToApiValues(create bool) string { // TODO write test func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } return } // CDROM @@ -187,7 +184,6 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i // Passthrough if storage.Passthrough != nil { // Create or Update - changes.MigrationImpossible = true params[id] = storage.Passthrough.mapToApiValues() return } else if currentStorage != nil && currentStorage.Passthrough != nil { @@ -195,6 +191,10 @@ func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, i changes.Delete = AddToList(changes.Delete, id) return } + // Delete if no subtype was specified + if currentStorage != nil { + changes.Delete = AddToList(changes.Delete, id) + } } // TODO write test diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index e28d7459..bf1f8642 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -144,9 +144,6 @@ func (storage QemuSataStorage) mapToApiValues(create bool) string { // TODO write test func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } return } // CDROM @@ -199,7 +196,6 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, // Passthrough if storage.Passthrough != nil { // Create or Update - changes.MigrationImpossible = true params[id] = storage.Passthrough.mapToApiValues() return } else if currentStorage != nil && currentStorage.Passthrough != nil { @@ -207,6 +203,10 @@ func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, changes.Delete = AddToList(changes.Delete, id) return } + // Delete if no subtype was specified + if currentStorage != nil { + changes.Delete = AddToList(changes.Delete, id) + } } // TODO write test diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 28d48598..8b2ff2d0 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -302,9 +302,6 @@ func (storage QemuScsiStorage) mapToApiValues(create bool) string { // TODO write test func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } return } // CDROM @@ -357,7 +354,6 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, // Passthrough if storage.Passthrough != nil { // Create or Update - changes.MigrationImpossible = true params[id] = storage.Passthrough.mapToApiValues() return } else if currentStorage != nil && currentStorage.Passthrough != nil { @@ -365,6 +361,10 @@ func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, changes.Delete = AddToList(changes.Delete, id) return } + // Delete if no subtype was specified + if currentStorage != nil { + changes.Delete = AddToList(changes.Delete, id) + } } // TODO write test diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index c448df05..3f1791b3 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -205,9 +205,6 @@ func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { // TODO write test func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } return } // CDROM @@ -260,7 +257,6 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor // Passthrough if storage.Passthrough != nil { // Create or Update - changes.MigrationImpossible = true params[id] = storage.Passthrough.mapToApiValues() return } else if currentStorage != nil && currentStorage.Passthrough != nil { @@ -268,6 +264,10 @@ func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStor changes.Delete = AddToList(changes.Delete, id) return } + // Delete if no subtype was specified + if currentStorage != nil { + changes.Delete = AddToList(changes.Delete, id) + } } // TODO write test From 92dd6f501302277f4dfaf8fdacb8672206cec667 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:41:31 +0000 Subject: [PATCH 030/191] feat: Make Size property read only --- proxmox/config_qemu_disk_ide.go | 3 +-- proxmox/config_qemu_disk_sata.go | 3 +-- proxmox/config_qemu_disk_scsi.go | 3 +-- proxmox/config_qemu_disk_virtio.go | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 5445f090..f7fab97d 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -85,7 +85,7 @@ type QemuIdePassthrough struct { File string Replicate bool Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint + Size uint //size is only returned and setting it has no effect } // TODO write test @@ -100,7 +100,6 @@ func (passthrough QemuIdePassthrough) mapToApiValues() string { File: passthrough.File, Replicate: passthrough.Replicate, Serial: passthrough.Serial, - Size: passthrough.Size, Type: ide, }.mapToApiValues(false) } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index bf1f8642..494e4fad 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -97,7 +97,7 @@ type QemuSataPassthrough struct { File string Replicate bool Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint + Size uint //size is only returned and setting it has no effect } // TODO write test @@ -112,7 +112,6 @@ func (passthrough QemuSataPassthrough) mapToApiValues() string { File: passthrough.File, Replicate: passthrough.Replicate, Serial: passthrough.Serial, - Size: passthrough.Size, Type: sata, }.mapToApiValues(false) } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 8b2ff2d0..38cb8e67 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -253,7 +253,7 @@ type QemuScsiPassthrough struct { ReadOnly bool Replicate bool Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint + Size uint //size is only returned and setting it has no effect } // TODO write test @@ -270,7 +270,6 @@ func (passthrough QemuScsiPassthrough) mapToApiValues() string { ReadOnly: passthrough.ReadOnly, Replicate: passthrough.Replicate, Serial: passthrough.Serial, - Size: passthrough.Size, Type: scsi, }.mapToApiValues(false) } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 3f1791b3..0c2b515e 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -158,7 +158,7 @@ type QemuVirtIOPassthrough struct { IOThread bool ReadOnly bool Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint + Size uint //size is only returned and setting it has no effect } // TODO write test @@ -173,7 +173,6 @@ func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { IOThread: passthrough.IOThread, ReadOnly: passthrough.ReadOnly, Serial: passthrough.Serial, - Size: passthrough.Size, Type: scsi, }.mapToApiValues(false) } From 00f46538d15a9b5278d57c928570054bf0e26682 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:32:00 +0000 Subject: [PATCH 031/191] refactor: Put in alphabetical order --- proxmox/config_qemu.go | 75 ++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 88b6158e..e9adb27d 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -35,56 +35,53 @@ type AgentNetworkInterface struct { // ConfigQemu - Proxmox API QEMU options type ConfigQemu struct { - VmID int `json:"vmid,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - Pool string `json:"pool,omitempty"` + Agent int `json:"agent,omitempty"` + Args string `json:"args,omitempty"` + Balloon int `json:"balloon,omitempty"` Bios string `json:"bios,omitempty"` + Boot string `json:"boot,omitempty"` + BootDisk string `json:"bootdisk,omitempty"` // Only returned as it's deprecated in the proxmox api + CIcustom string `json:"cicustom,omitempty"` // cloud-init option + CIpassword string `json:"cipassword,omitempty"` // cloud-init option + CIuser string `json:"ciuser,omitempty"` // cloud-init option + Description string `json:"description,omitempty"` + Disks *QemuStorages `json:"disks,omitempty"` EFIDisk QemuDevice `json:"efidisk,omitempty"` + FullClone *int `json:"fullclone,omitempty"` + HaGroup string `json:"hagroup,omitempty"` + HaState string `json:"hastate,omitempty"` + Hookscript string `json:"hookscript,omitempty"` + Hotplug string `json:"hotplug,omitempty"` + Ipconfig IpconfigMap `json:"ipconfig,omitempty"` // cloud-init option Machine string `json:"machine,omitempty"` - Onboot *bool `json:"onboot,omitempty"` - Startup string `json:"startup,omitempty"` - Tablet *bool `json:"tablet,omitempty"` - Agent int `json:"agent,omitempty"` Memory int `json:"memory,omitempty"` - Balloon int `json:"balloon,omitempty"` - QemuOs string `json:"ostype,omitempty"` + Name string `json:"name,omitempty"` + Nameserver string `json:"nameserver,omitempty"` // cloud-init option + Onboot *bool `json:"onboot,omitempty"` + Pool string `json:"pool,omitempty"` QemuCores int `json:"cores,omitempty"` - QemuSockets int `json:"sockets,omitempty"` - QemuVcpus int `json:"vcpus,omitempty"` QemuCpu string `json:"cpu,omitempty"` - QemuNuma *bool `json:"numa,omitempty"` - QemuKVM *bool `json:"kvm,omitempty"` - Hotplug string `json:"hotplug,omitempty"` - QemuIso string `json:"iso,omitempty"` - QemuPxe bool `json:"pxe,omitempty"` - FullClone *int `json:"fullclone,omitempty"` - Boot string `json:"boot,omitempty"` - BootDisk string `json:"bootdisk,omitempty"` // Only returned as it's deprecated in the proxmox api - Scsihw string `json:"scsihw,omitempty"` - Disks *QemuStorages `json:"disks,omitempty"` QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead - QemuUnusedDisks QemuDevices `json:"unused,omitempty"` - QemuVga QemuDevice `json:"vga,omitempty"` + QemuIso string `json:"iso,omitempty"` + QemuKVM *bool `json:"kvm,omitempty"` QemuNetworks QemuDevices `json:"network,omitempty"` + QemuNuma *bool `json:"numa,omitempty"` + QemuOs string `json:"ostype,omitempty"` + QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` + QemuPxe bool `json:"pxe,omitempty"` QemuSerials QemuDevices `json:"serial,omitempty"` + QemuSockets int `json:"sockets,omitempty"` + QemuUnusedDisks QemuDevices `json:"unused,omitempty"` QemuUsbs QemuDevices `json:"usb,omitempty"` - QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` - Hookscript string `json:"hookscript,omitempty"` - HaState string `json:"hastate,omitempty"` - HaGroup string `json:"hagroup,omitempty"` + QemuVcpus int `json:"vcpus,omitempty"` + QemuVga QemuDevice `json:"vga,omitempty"` + Scsihw string `json:"scsihw,omitempty"` + Searchdomain string `json:"searchdomain,omitempty"` // cloud-init option + Sshkeys string `json:"sshkeys,omitempty"` + Startup string `json:"startup,omitempty"` + Tablet *bool `json:"tablet,omitempty"` Tags string `json:"tags,omitempty"` - Args string `json:"args,omitempty"` - - // cloud-init options - CIuser string `json:"ciuser,omitempty"` - CIpassword string `json:"cipassword,omitempty"` - CIcustom string `json:"cicustom,omitempty"` - Ipconfig IpconfigMap `json:"ipconfig,omitempty"` - - Searchdomain string `json:"searchdomain,omitempty"` - Nameserver string `json:"nameserver,omitempty"` - Sshkeys string `json:"sshkeys,omitempty"` + VmID int `json:"vmid,omitempty"` } // CreateVm - Tell Proxmox API to make the VM From 7c58c8075b93dc15c24a114cd666bdffdad997b4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:47:06 +0000 Subject: [PATCH 032/191] Add TODO for future refactors --- proxmox/config_qemu.go | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index e9adb27d..9b3e57c4 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -35,53 +35,53 @@ type AgentNetworkInterface struct { // ConfigQemu - Proxmox API QEMU options type ConfigQemu struct { - Agent int `json:"agent,omitempty"` + Agent int `json:"agent,omitempty"` // TODO should probably be a bool Args string `json:"args,omitempty"` - Balloon int `json:"balloon,omitempty"` + Balloon int `json:"balloon,omitempty"` // TODO should probably be a bool Bios string `json:"bios,omitempty"` - Boot string `json:"boot,omitempty"` + Boot string `json:"boot,omitempty"` // TODO should be an array of custom enums BootDisk string `json:"bootdisk,omitempty"` // Only returned as it's deprecated in the proxmox api - CIcustom string `json:"cicustom,omitempty"` // cloud-init option - CIpassword string `json:"cipassword,omitempty"` // cloud-init option - CIuser string `json:"ciuser,omitempty"` // cloud-init option + CIcustom string `json:"cicustom,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + CIpassword string `json:"cipassword,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + CIuser string `json:"ciuser,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) Description string `json:"description,omitempty"` Disks *QemuStorages `json:"disks,omitempty"` - EFIDisk QemuDevice `json:"efidisk,omitempty"` - FullClone *int `json:"fullclone,omitempty"` + EFIDisk QemuDevice `json:"efidisk,omitempty"` // TODO should be a struct + FullClone *int `json:"fullclone,omitempty"` // TODO should probably be a bool HaGroup string `json:"hagroup,omitempty"` - HaState string `json:"hastate,omitempty"` + HaState string `json:"hastate,omitempty"` // TODO should be custom type with enum Hookscript string `json:"hookscript,omitempty"` - Hotplug string `json:"hotplug,omitempty"` - Ipconfig IpconfigMap `json:"ipconfig,omitempty"` // cloud-init option - Machine string `json:"machine,omitempty"` - Memory int `json:"memory,omitempty"` - Name string `json:"name,omitempty"` - Nameserver string `json:"nameserver,omitempty"` // cloud-init option + Hotplug string `json:"hotplug,omitempty"` // TODO should be a struct + Ipconfig IpconfigMap `json:"ipconfig,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + Machine string `json:"machine,omitempty"` // TODO should be custom type with enum + Memory int `json:"memory,omitempty"` // TODO should be uint + Name string `json:"name,omitempty"` // TODO should be custom type as there are character and length limitations + Nameserver string `json:"nameserver,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) Onboot *bool `json:"onboot,omitempty"` - Pool string `json:"pool,omitempty"` - QemuCores int `json:"cores,omitempty"` - QemuCpu string `json:"cpu,omitempty"` - QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead - QemuIso string `json:"iso,omitempty"` + Pool string `json:"pool,omitempty"` // TODO should be custom type as there are character and length limitations + QemuCores int `json:"cores,omitempty"` // TODO should be uint + QemuCpu string `json:"cpu,omitempty"` // TODO should be custom type with enum + QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead + QemuIso string `json:"iso,omitempty"` // TODO should be a struct QemuKVM *bool `json:"kvm,omitempty"` - QemuNetworks QemuDevices `json:"network,omitempty"` + QemuNetworks QemuDevices `json:"network,omitempty"` // TODO should be a struct QemuNuma *bool `json:"numa,omitempty"` QemuOs string `json:"ostype,omitempty"` - QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` + QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` // TODO should be a struct QemuPxe bool `json:"pxe,omitempty"` - QemuSerials QemuDevices `json:"serial,omitempty"` - QemuSockets int `json:"sockets,omitempty"` - QemuUnusedDisks QemuDevices `json:"unused,omitempty"` - QemuUsbs QemuDevices `json:"usb,omitempty"` - QemuVcpus int `json:"vcpus,omitempty"` - QemuVga QemuDevice `json:"vga,omitempty"` - Scsihw string `json:"scsihw,omitempty"` - Searchdomain string `json:"searchdomain,omitempty"` // cloud-init option - Sshkeys string `json:"sshkeys,omitempty"` - Startup string `json:"startup,omitempty"` + QemuSerials QemuDevices `json:"serial,omitempty"` // TODO should be a struct + QemuSockets int `json:"sockets,omitempty"` // TODO should be uint + QemuUnusedDisks QemuDevices `json:"unused,omitempty"` // TODO should be a struct + QemuUsbs QemuDevices `json:"usb,omitempty"` // TODO should be a struct + QemuVcpus int `json:"vcpus,omitempty"` // TODO should be uint + QemuVga QemuDevice `json:"vga,omitempty"` // TODO should be a struct + Scsihw string `json:"scsihw,omitempty"` // TODO should be custom type with enum + Searchdomain string `json:"searchdomain,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + Sshkeys string `json:"sshkeys,omitempty"` // TODO should be an array of strings + Startup string `json:"startup,omitempty"` // TODO should be a struct? Tablet *bool `json:"tablet,omitempty"` - Tags string `json:"tags,omitempty"` - VmID int `json:"vmid,omitempty"` + Tags string `json:"tags,omitempty"` // TODO should be an array of a custom type as there are character and length limitations + VmID int `json:"vmid,omitempty"` // TODO should be a custom type as there are limitations } // CreateVm - Tell Proxmox API to make the VM From 309c17980540e818786d4b2fd541910d782f68e4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 11 Mar 2023 22:17:40 +0000 Subject: [PATCH 033/191] refactor: QemuDiskBandwidth struct --- proxmox/config_qemu_disk.go | 68 +++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 055200ca..2b88a1ba 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -172,34 +172,34 @@ func (disk qemuDisk) mapToApiValues(create bool) (settings string) { // format // media - if disk.Bandwidth.ReadLimit_Iops.Concurrent >= 10 { - settings = settings + ",iops_rd=" + strconv.Itoa(int(disk.Bandwidth.ReadLimit_Iops.Concurrent)) + if disk.Bandwidth.Iops.ReadLimit.Concurrent >= 10 { + settings = settings + ",iops_rd=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Concurrent)) } - if disk.Bandwidth.ReadLimit_Iops.Burst >= 10 { - settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.ReadLimit_Iops.Burst)) + if disk.Bandwidth.Iops.ReadLimit.Burst >= 10 { + settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Burst)) } - if disk.Bandwidth.WriteLimit_Iops.Concurrent >= 10 { - settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.WriteLimit_Iops.Concurrent)) + if disk.Bandwidth.Iops.WriteLimit.Concurrent >= 10 { + settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Concurrent)) } - if disk.Bandwidth.WriteLimit_Iops.Burst >= 10 { - settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.WriteLimit_Iops.Burst)) + if disk.Bandwidth.Iops.WriteLimit.Burst >= 10 { + settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Burst)) } if (disk.Type == scsi || disk.Type == virtIO) && disk.IOThread { settings = settings + ",iothread=1" } - if disk.Bandwidth.ReadLimit_Data.Concurrent >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.ReadLimit_Data.Concurrent) + if disk.Bandwidth.Data.ReadLimit.Concurrent >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.Data.ReadLimit.Concurrent) } - if disk.Bandwidth.ReadLimit_Data.Burst >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.ReadLimit_Data.Burst) + if disk.Bandwidth.Data.ReadLimit.Burst >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.Data.ReadLimit.Burst) } - if disk.Bandwidth.WriteLimit_Data.Concurrent >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.WriteLimit_Data.Concurrent) + if disk.Bandwidth.Data.WriteLimit.Concurrent >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.Data.WriteLimit.Concurrent) } - if disk.Bandwidth.WriteLimit_Data.Burst >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.WriteLimit_Data.Burst) + if disk.Bandwidth.Data.WriteLimit.Burst >= float32(1) { + settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.Data.WriteLimit.Burst) } if !disk.Replicate { @@ -264,19 +264,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "iops_rd" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.ReadLimit_Iops.Concurrent = uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Concurrent = uint(tmp) } if e[0] == "iops_rd_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.ReadLimit_Iops.Burst = uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Burst = uint(tmp) } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.WriteLimit_Iops.Concurrent = uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Concurrent = uint(tmp) } if e[0] == "iops_wr_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.WriteLimit_Iops.Burst = uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Burst = uint(tmp) } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) @@ -284,19 +284,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "mbps_rd" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.ReadLimit_Data.Concurrent = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Concurrent = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_rd_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.ReadLimit_Data.Burst = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Burst = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.WriteLimit_Data.Concurrent = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Concurrent = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.WriteLimit_Data.Burst = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Burst = float32(math.Round(tmp*100) / 100) } if e[0] == "replicate" { disk.Replicate, _ = strconv.ParseBool(e[1]) @@ -339,18 +339,26 @@ func (asyncIO QemuDiskAsyncIO) Validate() error { } type QemuDiskBandwidth struct { - ReadLimit_Data QemuDisk_Bandwidth_Data - WriteLimit_Data QemuDisk_Bandwidth_Data - ReadLimit_Iops QemuDisk_Bandwidth_Iops - WriteLimit_Iops QemuDisk_Bandwidth_Iops + Data QemuDiskBandwidthData + Iops QemuDiskBandwidthIops } -type QemuDisk_Bandwidth_Data struct { +type QemuDiskBandwidthData struct { + ReadLimit QemuDiskBandwidthDataLimit + WriteLimit QemuDiskBandwidthDataLimit +} + +type QemuDiskBandwidthDataLimit struct { Concurrent float32 Burst float32 } -type QemuDisk_Bandwidth_Iops struct { +type QemuDiskBandwidthIops struct { + ReadLimit QemuDiskBandwidthIopsLimit + WriteLimit QemuDiskBandwidthIopsLimit +} + +type QemuDiskBandwidthIopsLimit struct { Concurrent uint Burst uint } From 54b29a5bb539c1d1eeb007c0ec34b2a48157cc01 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Sun, 12 Mar 2023 08:05:42 +0000 Subject: [PATCH 034/191] Vagrant testing on mac --- Vagrantfile | 9 ++++++++- scripts/vagrant-bootstrap.sh | 9 +++++++-- test/cli/Guest/Qemu/GuestQemu_100_test.go | 4 ++-- test/cli/preperations.go | 4 ++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 65e8f64f..196b3eb4 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,5 +1,5 @@ Vagrant.configure("2") do |config| - config.vm.box = "debian/buster64" + config.vm.box = "generic/debian11" config.vm.boot_timeout = 1800 config.vm.synced_folder ".", "/vagrant", disabled: true @@ -18,6 +18,13 @@ Vagrant.configure("2") do |config| config.vm.provider :virtualbox do |vb| vb.memory = 2048 vb.cpus = 2 + vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"] + end + + config.vm.provider :vmware do |vm| + vm.vmx["memsize"] = "2048" + vm.vmx["numvcpus"] = "2" + vm.vmx["vhv.enable"] = "TRUE" end config.vm.provider :libvirt do |v, override| diff --git a/scripts/vagrant-bootstrap.sh b/scripts/vagrant-bootstrap.sh index dcde89a0..4891c14f 100644 --- a/scripts/vagrant-bootstrap.sh +++ b/scripts/vagrant-bootstrap.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +hostnamectl set-hostname pve + export DEBIAN_FRONTEND=noninteractive # ensure required utilities are installed @@ -14,8 +16,11 @@ if [ -z "$(grep ${PVE_IP} /etc/hosts)" ]; then fi # add proxmox repository and its key -apt-add-repository 'deb http://download.proxmox.com/debian/pve buster pve-no-subscription' -wget -qO- http://download.proxmox.com/debian/proxmox-ve-release-6.x.gpg | apt-key add - +echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bullseye pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list +wget https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bullseye.gpg + +# disable source-directory +sed -i 's$source-directory /etc/network/interfaces.d$#source-directory /etc/network/interfaces.d$g' /etc/network/interfaces # update repositories and system apt-get update diff --git a/test/cli/Guest/Qemu/GuestQemu_100_test.go b/test/cli/Guest/Qemu/GuestQemu_100_test.go index b0e74e97..b550855c 100644 --- a/test/cli/Guest/Qemu/GuestQemu_100_test.go +++ b/test/cli/Guest/Qemu/GuestQemu_100_test.go @@ -25,7 +25,7 @@ func Test_GuestQemu_100_Create(t *testing.T) { "bios": "seabios", "tablet": true, "memory": 128, - "os": "l26", + "ostype": "l26", "cores": 1, "sockets": 1, "cpu": "host", @@ -60,7 +60,7 @@ func Test_GuestQemu_100_Get(t *testing.T) { "onboot": true, "tablet": true, "memory": 128, - "os": "l26", + "ostype": "l26", "cores": 1, "sockets": 1, "cpu": "host", diff --git a/test/cli/preperations.go b/test/cli/preperations.go index 08898b6b..abbfc5c0 100644 --- a/test/cli/preperations.go +++ b/test/cli/preperations.go @@ -5,7 +5,7 @@ import ( ) func SetEnvironmentVariables() { - os.Setenv("PM_API_URL", "https://192.168.67.50:8006/api2/json") + os.Setenv("PM_API_URL", "https://127.0.0.1:8006/api2/json") os.Setenv("PM_USER", "root@pam") - os.Setenv("PM_PASS", "Enter123!") + os.Setenv("PM_PASS", "root") } From 1864a51c6ec388e9778de20f4bfd4fcc5019cef5 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:32:40 +0000 Subject: [PATCH 035/191] refactor: consolidate code for creating/updating disks --- proxmox/config_qemu_disk.go | 109 ++++++++++++++--- proxmox/config_qemu_disk_ide.go | 130 +++++++++----------- proxmox/config_qemu_disk_sata.go | 134 +++++++++----------- proxmox/config_qemu_disk_scsi.go | 189 +++++++++++++---------------- proxmox/config_qemu_disk_virtio.go | 155 +++++++++++------------ 5 files changed, 360 insertions(+), 357 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 2b88a1ba..f12a14c2 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -132,7 +132,7 @@ type qemuDisk struct { // TODO custom type File string // Only set for Passthrough. Format QemuDiskFormat - ID uint // Only set for Disk + Id uint // Only set for Disk IOThread bool // Only set for scsi,virtio Number uint ReadOnly bool // Only set for scsi,virtio @@ -145,9 +145,11 @@ type qemuDisk struct { } // TODO write test -func (disk qemuDisk) mapToApiValues(create bool) (settings string) { - if create { - if disk.Storage != "" { +func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { + if disk.Storage != "" { + if create { + settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) + } else { settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) } } @@ -237,7 +239,7 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(idAndFormat) == 2 { tmp := strings.Split(idAndFormat[1], ".") tmpId, _ := strconv.Atoi(tmp[0]) - disk.ID = uint(tmpId) + disk.Id = uint(tmpId) if len(tmp) == 2 { disk.Format = QemuDiskFormat(tmp[1]) } @@ -430,6 +432,83 @@ const ( virtIO qemuDiskType = 3 ) +type qemuStorage struct { + CdRom *QemuCdRom `json:"cdrom,omitempty"` + CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` + Disk *qemuDisk `json:"disk,omitempty"` + Passthrough *qemuDisk `json:"passthrough,omitempty"` +} + +func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + if storage == nil { + return + } + // CDROM + if storage.CdRom != nil { + // Create or Update + params[id] = storage.CdRom.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CdRom != nil { + // Delete + changes.Delete = AddToList(changes.Delete, id) + return + } + // CloudInit + if storage.CloudInit != nil { + // Create or Update + params[id] = storage.CloudInit.mapToApiValues() + return + } else if currentStorage != nil && currentStorage.CloudInit != nil { + // Delete + changes.Delete = AddToList(changes.Delete, id) + return + } + // Disk + if storage.Disk != nil { + if currentStorage == nil || currentStorage.Disk == nil { + // Create + params[id] = storage.Disk.mapToApiValues(vmID, true) + } else { + if storage.Disk.Size >= currentStorage.Disk.Size { + // Update + if storage.Disk.Id == 0 { + storage.Disk.Id = currentStorage.Disk.Id + } + if storage.Disk.Storage != currentStorage.Disk.Storage { + changes.Move = append(changes.Move, qemuDiskShort{ + Id: id, + Storage: storage.Disk.Storage, + }) + } + params[id] = storage.Disk.mapToApiValues(vmID, false) + } else { + // Delete and Create + changes.Delete = AddToList(changes.Delete, id) + params[id] = storage.Disk.mapToApiValues(vmID, true) + } + } + return + } else if currentStorage != nil && currentStorage.Disk != nil { + // Delete + changes.Delete = AddToList(changes.Delete, id) + return + } + // Passthrough + if storage.Passthrough != nil { + // Create or Update + params[id] = storage.Passthrough.mapToApiValues(0, false) + return + } else if currentStorage != nil && currentStorage.Passthrough != nil { + // Delete + changes.Delete = AddToList(changes.Delete, id) + return + } + // Delete if no subtype was specified + if currentStorage != nil { + changes.Delete = AddToList(changes.Delete, id) + } +} + type QemuStorages struct { Ide *QemuIdeDisks `json:"ide,omitempty"` Sata *QemuSataDisks `json:"sata,omitempty"` @@ -437,35 +516,35 @@ type QemuStorages struct { VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` } -func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, params map[string]interface{}) *qemuUpdateChanges { +func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID uint, params map[string]interface{}) *qemuUpdateChanges { changes := &qemuUpdateChanges{} if currentStorages.Ide != nil { - storages.Ide.mapToApiValues(currentStorages.Ide, params, changes) + storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, changes) } if currentStorages.Sata != nil { - storages.Sata.mapToApiValues(currentStorages.Sata, params, changes) + storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, changes) } if currentStorages.Scsi != nil { - storages.Scsi.mapToApiValues(currentStorages.Scsi, params, changes) + storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, changes) } if currentStorages.VirtIO != nil { - storages.VirtIO.mapToApiValues(currentStorages.VirtIO, params, changes) + storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, changes) } return changes } -func (storages QemuStorages) mapToApiValues(params map[string]interface{}) { +func (storages QemuStorages) mapToApiValues(vmID uint, params map[string]interface{}) { if storages.Ide != nil { - storages.Ide.mapToApiValues(nil, params, nil) + storages.Ide.mapToApiValues(nil, vmID, params, nil) } if storages.Sata != nil { - storages.Sata.mapToApiValues(nil, params, nil) + storages.Sata.mapToApiValues(nil, vmID, params, nil) } if storages.Scsi != nil { - storages.Scsi.mapToApiValues(nil, params, nil) + storages.Scsi.mapToApiValues(nil, vmID, params, nil) } if storages.VirtIO != nil { - storages.VirtIO.mapToApiValues(nil, params, nil) + storages.VirtIO.mapToApiValues(nil, vmID, params, nil) } } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index f7fab97d..d4c1304e 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -7,6 +7,7 @@ type QemuIdeDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Id uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` @@ -14,7 +15,7 @@ type QemuIdeDisk struct { } // TODO write test -func (disk QemuIdeDisk) mapToApiValues(create bool) string { +func (disk QemuIdeDisk) mapToApiValues(vmID uint, create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, Backup: disk.Backup, @@ -27,7 +28,7 @@ func (disk QemuIdeDisk) mapToApiValues(create bool) string { Size: disk.Size, Storage: disk.Storage, Type: ide, - }.mapToApiValues(create) + }.mapToApiValues(vmID, create) } type QemuIdeDisks struct { @@ -38,15 +39,15 @@ type QemuIdeDisks struct { } // TODO write test -func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { tmpCurrentDisks := QemuIdeDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "ide0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "ide1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "ide2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "ide3", params, changes) + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "ide0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "ide1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "ide2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "ide3", params, changes) } // TODO write test @@ -101,7 +102,7 @@ func (passthrough QemuIdePassthrough) mapToApiValues() string { Replicate: passthrough.Replicate, Serial: passthrough.Serial, Type: ide, - }.mapToApiValues(false) + }.mapToApiValues(0, false) } type QemuIdeStorage struct { @@ -112,9 +113,50 @@ type QemuIdeStorage struct { } // TODO write test -func (storage QemuIdeStorage) mapToApiValues(create bool) string { +// converts to qemuStorage +func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { + if storage == nil { + return nil + } + generalizedStorage := qemuStorage{ + CdRom: storage.CdRom, + CloudInit: storage.CloudInit, + } if storage.Disk != nil { - return storage.Disk.mapToApiValues(create) + generalizedStorage.Disk = &qemuDisk{ + AsyncIO: storage.Disk.AsyncIO, + Backup: storage.Disk.Backup, + Bandwidth: storage.Disk.Bandwidth, + Cache: storage.Disk.Cache, + Discard: storage.Disk.Discard, + EmulateSSD: storage.Disk.EmulateSSD, + Id: storage.Disk.Id, + Replicate: storage.Disk.Replicate, + Serial: storage.Disk.Serial, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + } + } + if storage.Passthrough != nil { + generalizedStorage.Passthrough = &qemuDisk{ + AsyncIO: storage.Passthrough.AsyncIO, + Backup: storage.Passthrough.Backup, + Bandwidth: storage.Passthrough.Bandwidth, + Cache: storage.Passthrough.Cache, + Discard: storage.Passthrough.Discard, + EmulateSSD: storage.Passthrough.EmulateSSD, + File: storage.Passthrough.File, + Replicate: storage.Passthrough.Replicate, + Serial: storage.Passthrough.Serial, + } + } + return &generalizedStorage +} + +// TODO write test +func (storage QemuIdeStorage) mapToApiValues(vmID uint, create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(vmID, create) } if storage.CdRom != nil { return storage.CdRom.mapToApiValues() @@ -129,71 +171,8 @@ func (storage QemuIdeStorage) mapToApiValues(create bool) string { } // TODO write test -func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - if storage == nil { - return - } - // CDROM - if storage.CdRom != nil { - // Create or Update - params[id] = storage.CdRom.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CdRom != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // CloudInit - if storage.CloudInit != nil { - // Create or Update - params[id] = storage.CloudInit.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CloudInit != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Disk - if storage.Disk != nil { - if currentStorage == nil || currentStorage.Disk == nil { - // Create - params[id] = storage.Disk.mapToApiValues(true) - } else { - if storage.Disk.Size >= currentStorage.Disk.Size { - // Update - if storage.Disk.Storage != currentStorage.Disk.Storage { - changes.Move = append(changes.Move, qemuDiskShort{ - Id: id, - Storage: storage.Disk.Storage, - }) - } - params[id] = storage.Disk.mapToApiValues(false) - } else { - // Delete and Create - changes.Delete = AddToList(changes.Delete, id) - params[id] = storage.Disk.mapToApiValues(true) - } - } - return - } else if currentStorage != nil && currentStorage.Disk != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Passthrough - if storage.Passthrough != nil { - // Create or Update - params[id] = storage.Passthrough.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.Passthrough != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Delete if no subtype was specified - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } +func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) } // TODO write test @@ -220,6 +199,7 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Id: tmpDisk.Id, Replicate: tmpDisk.Replicate, Serial: tmpDisk.Serial, Size: tmpDisk.Size, diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 494e4fad..bbe8287d 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -7,6 +7,7 @@ type QemuSataDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Id uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` @@ -14,7 +15,7 @@ type QemuSataDisk struct { } // TODO write test -func (disk QemuSataDisk) mapToApiValues(create bool) string { +func (disk QemuSataDisk) mapToApiValues(vmID uint, create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, Backup: disk.Backup, @@ -27,7 +28,7 @@ func (disk QemuSataDisk) mapToApiValues(create bool) string { Size: disk.Size, Storage: disk.Storage, Type: sata, - }.mapToApiValues(create) + }.mapToApiValues(vmID, create) } type QemuSataDisks struct { @@ -40,17 +41,17 @@ type QemuSataDisks struct { } // TODO write test -func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { tmpCurrentDisks := QemuSataDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "sata0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "sata1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "sata2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "sata3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "sata4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "sata5", params, changes) + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "sata0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "sata1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "sata2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "sata3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "sata4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "sata5", params, changes) } // TODO write test @@ -113,7 +114,7 @@ func (passthrough QemuSataPassthrough) mapToApiValues() string { Replicate: passthrough.Replicate, Serial: passthrough.Serial, Type: sata, - }.mapToApiValues(false) + }.mapToApiValues(0, false) } type QemuSataStorage struct { @@ -124,9 +125,50 @@ type QemuSataStorage struct { } // TODO write test -func (storage QemuSataStorage) mapToApiValues(create bool) string { +// converts to qemuStorage +func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { + if storage == nil { + return nil + } + generalizedStorage := qemuStorage{ + CdRom: storage.CdRom, + CloudInit: storage.CloudInit, + } if storage.Disk != nil { - return storage.Disk.mapToApiValues(create) + generalizedStorage.Disk = &qemuDisk{ + AsyncIO: storage.Disk.AsyncIO, + Backup: storage.Disk.Backup, + Bandwidth: storage.Disk.Bandwidth, + Cache: storage.Disk.Cache, + Discard: storage.Disk.Discard, + EmulateSSD: storage.Disk.EmulateSSD, + Id: storage.Disk.Id, + Replicate: storage.Disk.Replicate, + Serial: storage.Disk.Serial, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + } + } + if storage.Passthrough != nil { + generalizedStorage.Passthrough = &qemuDisk{ + AsyncIO: storage.Passthrough.AsyncIO, + Backup: storage.Passthrough.Backup, + Bandwidth: storage.Passthrough.Bandwidth, + Cache: storage.Passthrough.Cache, + Discard: storage.Passthrough.Discard, + EmulateSSD: storage.Passthrough.EmulateSSD, + File: storage.Passthrough.File, + Replicate: storage.Passthrough.Replicate, + Serial: storage.Passthrough.Serial, + } + } + return &generalizedStorage +} + +// TODO write test +func (storage QemuSataStorage) mapToApiValues(vmID uint, create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(vmID, create) } if storage.CdRom != nil { return storage.CdRom.mapToApiValues() @@ -141,71 +183,8 @@ func (storage QemuSataStorage) mapToApiValues(create bool) string { } // TODO write test -func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - if storage == nil { - return - } - // CDROM - if storage.CdRom != nil { - // Create or Update - params[id] = storage.CdRom.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CdRom != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // CloudInit - if storage.CloudInit != nil { - // Create or Update - params[id] = storage.CloudInit.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CloudInit != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Disk - if storage.Disk != nil { - if currentStorage == nil || currentStorage.Disk == nil { - // Create - params[id] = storage.Disk.mapToApiValues(true) - } else { - if storage.Disk.Size >= currentStorage.Disk.Size { - // Update - if storage.Disk.Storage != currentStorage.Disk.Storage { - changes.Move = append(changes.Move, qemuDiskShort{ - Id: id, - Storage: storage.Disk.Storage, - }) - } - params[id] = storage.Disk.mapToApiValues(false) - } else { - // Delete and Create - changes.Delete = AddToList(changes.Delete, id) - params[id] = storage.Disk.mapToApiValues(true) - } - } - return - } else if currentStorage != nil && currentStorage.Disk != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Passthrough - if storage.Passthrough != nil { - // Create or Update - params[id] = storage.Passthrough.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.Passthrough != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Delete if no subtype was specified - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } +func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) } // TODO write test @@ -232,6 +211,7 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Id: tmpDisk.Id, Replicate: tmpDisk.Replicate, Serial: tmpDisk.Serial, Size: tmpDisk.Size, diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 38cb8e67..05c202e4 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -7,6 +7,7 @@ type QemuScsiDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Id uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` @@ -16,7 +17,7 @@ type QemuScsiDisk struct { } // TODO write test -func (disk QemuScsiDisk) mapToApiValues(create bool) string { +func (disk QemuScsiDisk) mapToApiValues(vmID uint, create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, Backup: disk.Backup, @@ -31,7 +32,7 @@ func (disk QemuScsiDisk) mapToApiValues(create bool) string { Size: disk.Size, Storage: disk.Storage, Type: scsi, - }.mapToApiValues(create) + }.mapToApiValues(vmID, create) } type QemuScsiDisks struct { @@ -69,42 +70,42 @@ type QemuScsiDisks struct { } // TODO write test -func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { tmpCurrentDisks := QemuScsiDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "scsi0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "scsi1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "scsi2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "scsi3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "scsi4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "scsi5", params, changes) - disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, "scsi6", params, changes) - disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, "scsi7", params, changes) - disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, "scsi8", params, changes) - disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, "scsi9", params, changes) - disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, "scsi10", params, changes) - disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, "scsi11", params, changes) - disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, "scsi12", params, changes) - disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, "scsi13", params, changes) - disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, "scsi14", params, changes) - disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, "scsi15", params, changes) - disks.Disk_16.markDiskChanges(tmpCurrentDisks.Disk_16, "scsi16", params, changes) - disks.Disk_17.markDiskChanges(tmpCurrentDisks.Disk_17, "scsi17", params, changes) - disks.Disk_18.markDiskChanges(tmpCurrentDisks.Disk_18, "scsi18", params, changes) - disks.Disk_19.markDiskChanges(tmpCurrentDisks.Disk_19, "scsi19", params, changes) - disks.Disk_20.markDiskChanges(tmpCurrentDisks.Disk_20, "scsi20", params, changes) - disks.Disk_21.markDiskChanges(tmpCurrentDisks.Disk_21, "scsi21", params, changes) - disks.Disk_22.markDiskChanges(tmpCurrentDisks.Disk_22, "scsi22", params, changes) - disks.Disk_23.markDiskChanges(tmpCurrentDisks.Disk_23, "scsi23", params, changes) - disks.Disk_24.markDiskChanges(tmpCurrentDisks.Disk_24, "scsi24", params, changes) - disks.Disk_25.markDiskChanges(tmpCurrentDisks.Disk_25, "scsi25", params, changes) - disks.Disk_26.markDiskChanges(tmpCurrentDisks.Disk_26, "scsi26", params, changes) - disks.Disk_27.markDiskChanges(tmpCurrentDisks.Disk_27, "scsi27", params, changes) - disks.Disk_28.markDiskChanges(tmpCurrentDisks.Disk_28, "scsi28", params, changes) - disks.Disk_29.markDiskChanges(tmpCurrentDisks.Disk_29, "scsi29", params, changes) - disks.Disk_30.markDiskChanges(tmpCurrentDisks.Disk_30, "scsi30", params, changes) + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "scsi0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "scsi1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "scsi2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "scsi3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "scsi4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "scsi5", params, changes) + disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, vmID, "scsi6", params, changes) + disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, vmID, "scsi7", params, changes) + disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, vmID, "scsi8", params, changes) + disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, vmID, "scsi9", params, changes) + disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, vmID, "scsi10", params, changes) + disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, vmID, "scsi11", params, changes) + disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, vmID, "scsi12", params, changes) + disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, vmID, "scsi13", params, changes) + disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, vmID, "scsi14", params, changes) + disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, vmID, "scsi15", params, changes) + disks.Disk_16.markDiskChanges(tmpCurrentDisks.Disk_16, vmID, "scsi16", params, changes) + disks.Disk_17.markDiskChanges(tmpCurrentDisks.Disk_17, vmID, "scsi17", params, changes) + disks.Disk_18.markDiskChanges(tmpCurrentDisks.Disk_18, vmID, "scsi18", params, changes) + disks.Disk_19.markDiskChanges(tmpCurrentDisks.Disk_19, vmID, "scsi19", params, changes) + disks.Disk_20.markDiskChanges(tmpCurrentDisks.Disk_20, vmID, "scsi20", params, changes) + disks.Disk_21.markDiskChanges(tmpCurrentDisks.Disk_21, vmID, "scsi21", params, changes) + disks.Disk_22.markDiskChanges(tmpCurrentDisks.Disk_22, vmID, "scsi22", params, changes) + disks.Disk_23.markDiskChanges(tmpCurrentDisks.Disk_23, vmID, "scsi23", params, changes) + disks.Disk_24.markDiskChanges(tmpCurrentDisks.Disk_24, vmID, "scsi24", params, changes) + disks.Disk_25.markDiskChanges(tmpCurrentDisks.Disk_25, vmID, "scsi25", params, changes) + disks.Disk_26.markDiskChanges(tmpCurrentDisks.Disk_26, vmID, "scsi26", params, changes) + disks.Disk_27.markDiskChanges(tmpCurrentDisks.Disk_27, vmID, "scsi27", params, changes) + disks.Disk_28.markDiskChanges(tmpCurrentDisks.Disk_28, vmID, "scsi28", params, changes) + disks.Disk_29.markDiskChanges(tmpCurrentDisks.Disk_29, vmID, "scsi29", params, changes) + disks.Disk_30.markDiskChanges(tmpCurrentDisks.Disk_30, vmID, "scsi30", params, changes) } // TODO write test @@ -271,7 +272,7 @@ func (passthrough QemuScsiPassthrough) mapToApiValues() string { Replicate: passthrough.Replicate, Serial: passthrough.Serial, Type: scsi, - }.mapToApiValues(false) + }.mapToApiValues(0, false) } type QemuScsiStorage struct { @@ -282,9 +283,54 @@ type QemuScsiStorage struct { } // TODO write test -func (storage QemuScsiStorage) mapToApiValues(create bool) string { +// converts to qemuStorage +func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { + if storage == nil { + return nil + } + generalizedStorage := qemuStorage{ + CdRom: storage.CdRom, + CloudInit: storage.CloudInit, + } + if storage.Disk != nil { + generalizedStorage.Disk = &qemuDisk{ + AsyncIO: storage.Disk.AsyncIO, + Backup: storage.Disk.Backup, + Bandwidth: storage.Disk.Bandwidth, + Cache: storage.Disk.Cache, + Discard: storage.Disk.Discard, + EmulateSSD: storage.Disk.EmulateSSD, + Id: storage.Disk.Id, + IOThread: storage.Disk.IOThread, + ReadOnly: storage.Disk.ReadOnly, + Replicate: storage.Disk.Replicate, + Serial: storage.Disk.Serial, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + } + } + if storage.Passthrough != nil { + generalizedStorage.Passthrough = &qemuDisk{ + AsyncIO: storage.Passthrough.AsyncIO, + Backup: storage.Passthrough.Backup, + Bandwidth: storage.Passthrough.Bandwidth, + Cache: storage.Passthrough.Cache, + Discard: storage.Passthrough.Discard, + EmulateSSD: storage.Passthrough.EmulateSSD, + File: storage.Passthrough.File, + IOThread: storage.Passthrough.IOThread, + ReadOnly: storage.Passthrough.ReadOnly, + Replicate: storage.Passthrough.Replicate, + Serial: storage.Passthrough.Serial, + } + } + return &generalizedStorage +} + +// TODO write test +func (storage QemuScsiStorage) mapToApiValues(vmID uint, create bool) string { if storage.Disk != nil { - return storage.Disk.mapToApiValues(create) + return storage.Disk.mapToApiValues(vmID, create) } if storage.CdRom != nil { return storage.CdRom.mapToApiValues() @@ -299,71 +345,8 @@ func (storage QemuScsiStorage) mapToApiValues(create bool) string { } // TODO write test -func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - if storage == nil { - return - } - // CDROM - if storage.CdRom != nil { - // Create or Update - params[id] = storage.CdRom.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CdRom != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // CloudInit - if storage.CloudInit != nil { - // Create or Update - params[id] = storage.CloudInit.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CloudInit != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Disk - if storage.Disk != nil { - if currentStorage == nil || currentStorage.Disk == nil { - // Create - params[id] = storage.Disk.mapToApiValues(true) - } else { - if storage.Disk.Size >= currentStorage.Disk.Size { - // Update - if storage.Disk.Storage != currentStorage.Disk.Storage { - changes.Move = append(changes.Move, qemuDiskShort{ - Id: id, - Storage: storage.Disk.Storage, - }) - } - params[id] = storage.Disk.mapToApiValues(false) - } else { - // Delete and Create - changes.Delete = AddToList(changes.Delete, id) - params[id] = storage.Disk.mapToApiValues(true) - } - } - return - } else if currentStorage != nil && currentStorage.Disk != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Passthrough - if storage.Passthrough != nil { - // Create or Update - params[id] = storage.Passthrough.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.Passthrough != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Delete if no subtype was specified - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) - } +func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) } // TODO write test @@ -390,6 +373,7 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Id: tmpDisk.Id, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, Replicate: tmpDisk.Replicate, @@ -412,5 +396,4 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} - } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 0c2b515e..97feb0e4 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -6,6 +6,7 @@ type QemuVirtIODisk struct { Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` + Id uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` @@ -15,7 +16,7 @@ type QemuVirtIODisk struct { } // TODO write test -func (disk QemuVirtIODisk) mapToApiValues(create bool) string { +func (disk QemuVirtIODisk) mapToApiValues(vmID uint, create bool) string { return qemuDisk{ AsyncIO: disk.AsyncIO, Backup: disk.Backup, @@ -28,7 +29,7 @@ func (disk QemuVirtIODisk) mapToApiValues(create bool) string { Size: disk.Size, Storage: disk.Storage, Type: virtIO, - }.mapToApiValues(create) + }.mapToApiValues(vmID, create) } type QemuVirtIODisks struct { @@ -51,27 +52,27 @@ type QemuVirtIODisks struct { } // TODO write test -func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { tmpCurrentDisks := QemuVirtIODisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, "virtio0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, "virtio1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, "virtio2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, "virtio3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, "virtio4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, "virtio5", params, changes) - disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, "virtio6", params, changes) - disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, "virtio7", params, changes) - disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, "virtio8", params, changes) - disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, "virtio9", params, changes) - disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, "virtio10", params, changes) - disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, "virtio11", params, changes) - disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, "virtio12", params, changes) - disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, "virtio13", params, changes) - disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, "virtio14", params, changes) - disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, "virtio15", params, changes) + disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "virtio0", params, changes) + disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "virtio1", params, changes) + disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "virtio2", params, changes) + disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "virtio3", params, changes) + disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "virtio4", params, changes) + disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "virtio5", params, changes) + disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, vmID, "virtio6", params, changes) + disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, vmID, "virtio7", params, changes) + disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, vmID, "virtio8", params, changes) + disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, vmID, "virtio9", params, changes) + disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, vmID, "virtio10", params, changes) + disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, vmID, "virtio11", params, changes) + disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, vmID, "virtio12", params, changes) + disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, vmID, "virtio13", params, changes) + disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, vmID, "virtio14", params, changes) + disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, vmID, "virtio15", params, changes) } // TODO write test @@ -174,7 +175,7 @@ func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { ReadOnly: passthrough.ReadOnly, Serial: passthrough.Serial, Type: scsi, - }.mapToApiValues(false) + }.mapToApiValues(0, false) } type QemuVirtIOStorage struct { @@ -185,88 +186,67 @@ type QemuVirtIOStorage struct { } // TODO write test -func (storage QemuVirtIOStorage) mapToApiValues(create bool) string { - if storage.Disk != nil { - return storage.Disk.mapToApiValues(create) +// converts to qemuStorage +func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { + if storage == nil { + return nil } - if storage.CdRom != nil { - return storage.CdRom.mapToApiValues() + generalizedStorage := qemuStorage{ + CdRom: storage.CdRom, + CloudInit: storage.CloudInit, } - if storage.CloudInit != nil { - return storage.CloudInit.mapToApiValues() + if storage.Disk != nil { + generalizedStorage.Disk = &qemuDisk{ + AsyncIO: storage.Disk.AsyncIO, + Backup: storage.Disk.Backup, + Bandwidth: storage.Disk.Bandwidth, + Cache: storage.Disk.Cache, + Discard: storage.Disk.Discard, + Id: storage.Disk.Id, + IOThread: storage.Disk.IOThread, + ReadOnly: storage.Disk.ReadOnly, + Replicate: storage.Disk.Replicate, + Serial: storage.Disk.Serial, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + } } if storage.Passthrough != nil { - return storage.Passthrough.mapToApiValues() + generalizedStorage.Passthrough = &qemuDisk{ + AsyncIO: storage.Passthrough.AsyncIO, + Backup: storage.Passthrough.Backup, + Bandwidth: storage.Passthrough.Bandwidth, + Cache: storage.Passthrough.Cache, + Discard: storage.Passthrough.Discard, + File: storage.Passthrough.File, + IOThread: storage.Passthrough.IOThread, + ReadOnly: storage.Passthrough.ReadOnly, + Serial: storage.Passthrough.Serial, + } } - return "" + return &generalizedStorage } // TODO write test -func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - if storage == nil { - return +func (storage QemuVirtIOStorage) mapToApiValues(vmID uint, create bool) string { + if storage.Disk != nil { + return storage.Disk.mapToApiValues(vmID, create) } - // CDROM if storage.CdRom != nil { - // Create or Update - params[id] = storage.CdRom.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CdRom != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return + return storage.CdRom.mapToApiValues() } - // CloudInit if storage.CloudInit != nil { - // Create or Update - params[id] = storage.CloudInit.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.CloudInit != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Disk - if storage.Disk != nil { - if currentStorage == nil || currentStorage.Disk == nil { - // Create - params[id] = storage.Disk.mapToApiValues(true) - } else { - if storage.Disk.Size >= currentStorage.Disk.Size { - // Update - if storage.Disk.Storage != currentStorage.Disk.Storage { - changes.Move = append(changes.Move, qemuDiskShort{ - Id: id, - Storage: storage.Disk.Storage, - }) - } - params[id] = storage.Disk.mapToApiValues(false) - } else { - // Delete and Create - changes.Delete = AddToList(changes.Delete, id) - params[id] = storage.Disk.mapToApiValues(true) - } - } - return - } else if currentStorage != nil && currentStorage.Disk != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return + return storage.CloudInit.mapToApiValues() } - // Passthrough if storage.Passthrough != nil { - // Create or Update - params[id] = storage.Passthrough.mapToApiValues() - return - } else if currentStorage != nil && currentStorage.Passthrough != nil { - // Delete - changes.Delete = AddToList(changes.Delete, id) - return - } - // Delete if no subtype was specified - if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) + return storage.Passthrough.mapToApiValues() } + return "" +} + +// TODO write test +func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { + storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) } // TODO write test @@ -292,6 +272,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { Bandwidth: tmpDisk.Bandwidth, Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, + Id: tmpDisk.Id, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, Replicate: tmpDisk.Replicate, From d338e78a2991dd00fcec97805cc3f0a19b9a4952 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:33:39 +0000 Subject: [PATCH 036/191] fix: decoding of disk id --- proxmox/config_qemu_disk.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f12a14c2..afd4fd2c 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -235,13 +235,13 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { diskAndNumberAndFormat := strings.Split(settings[0][0], ":") disk.Storage = diskAndNumberAndFormat[0] if len(diskAndNumberAndFormat) == 2 { - idAndFormat := strings.Split(diskAndNumberAndFormat[1], "-") + idAndFormat := strings.Split(diskAndNumberAndFormat[1], ".") if len(idAndFormat) == 2 { - tmp := strings.Split(idAndFormat[1], ".") - tmpId, _ := strconv.Atoi(tmp[0]) - disk.Id = uint(tmpId) - if len(tmp) == 2 { - disk.Format = QemuDiskFormat(tmp[1]) + disk.Format = QemuDiskFormat(idAndFormat[1]) + tmp := strings.Split(idAndFormat[0], "-") + if len(tmp) > 1 { + tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) + disk.Id = uint(tmpId) } } } From 1d567af29bd15581386e7274d735e587a9ec1504 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:46:50 +0000 Subject: [PATCH 037/191] refactor: remove unnecessary function --- proxmox/config_qemu_disk_ide.go | 13 ++---- proxmox/config_qemu_disk_sata.go | 17 +++----- proxmox/config_qemu_disk_scsi.go | 67 ++++++++++++++---------------- proxmox/config_qemu_disk_virtio.go | 37 +++++++---------- 4 files changed, 57 insertions(+), 77 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index d4c1304e..9e1aefad 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -44,10 +44,10 @@ func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "ide0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "ide1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "ide2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "ide3", params, changes) + disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "ide0", params, changes) + disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "ide1", params, changes) + disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "ide2", params, changes) + disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "ide3", params, changes) } // TODO write test @@ -170,11 +170,6 @@ func (storage QemuIdeStorage) mapToApiValues(vmID uint, create bool) string { return "" } -// TODO write test -func (storage *QemuIdeStorage) markDiskChanges(currentStorage *QemuIdeStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) -} - // TODO write test func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index bbe8287d..bb640026 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -46,12 +46,12 @@ func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "sata0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "sata1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "sata2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "sata3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "sata4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "sata5", params, changes) + disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "sata0", params, changes) + disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "sata1", params, changes) + disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "sata2", params, changes) + disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "sata3", params, changes) + disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "sata4", params, changes) + disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "sata5", params, changes) } // TODO write test @@ -182,11 +182,6 @@ func (storage QemuSataStorage) mapToApiValues(vmID uint, create bool) string { return "" } -// TODO write test -func (storage *QemuSataStorage) markDiskChanges(currentStorage *QemuSataStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) -} - // TODO write test func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 05c202e4..af094d72 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -75,37 +75,37 @@ func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "scsi0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "scsi1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "scsi2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "scsi3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "scsi4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "scsi5", params, changes) - disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, vmID, "scsi6", params, changes) - disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, vmID, "scsi7", params, changes) - disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, vmID, "scsi8", params, changes) - disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, vmID, "scsi9", params, changes) - disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, vmID, "scsi10", params, changes) - disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, vmID, "scsi11", params, changes) - disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, vmID, "scsi12", params, changes) - disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, vmID, "scsi13", params, changes) - disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, vmID, "scsi14", params, changes) - disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, vmID, "scsi15", params, changes) - disks.Disk_16.markDiskChanges(tmpCurrentDisks.Disk_16, vmID, "scsi16", params, changes) - disks.Disk_17.markDiskChanges(tmpCurrentDisks.Disk_17, vmID, "scsi17", params, changes) - disks.Disk_18.markDiskChanges(tmpCurrentDisks.Disk_18, vmID, "scsi18", params, changes) - disks.Disk_19.markDiskChanges(tmpCurrentDisks.Disk_19, vmID, "scsi19", params, changes) - disks.Disk_20.markDiskChanges(tmpCurrentDisks.Disk_20, vmID, "scsi20", params, changes) - disks.Disk_21.markDiskChanges(tmpCurrentDisks.Disk_21, vmID, "scsi21", params, changes) - disks.Disk_22.markDiskChanges(tmpCurrentDisks.Disk_22, vmID, "scsi22", params, changes) - disks.Disk_23.markDiskChanges(tmpCurrentDisks.Disk_23, vmID, "scsi23", params, changes) - disks.Disk_24.markDiskChanges(tmpCurrentDisks.Disk_24, vmID, "scsi24", params, changes) - disks.Disk_25.markDiskChanges(tmpCurrentDisks.Disk_25, vmID, "scsi25", params, changes) - disks.Disk_26.markDiskChanges(tmpCurrentDisks.Disk_26, vmID, "scsi26", params, changes) - disks.Disk_27.markDiskChanges(tmpCurrentDisks.Disk_27, vmID, "scsi27", params, changes) - disks.Disk_28.markDiskChanges(tmpCurrentDisks.Disk_28, vmID, "scsi28", params, changes) - disks.Disk_29.markDiskChanges(tmpCurrentDisks.Disk_29, vmID, "scsi29", params, changes) - disks.Disk_30.markDiskChanges(tmpCurrentDisks.Disk_30, vmID, "scsi30", params, changes) + disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "scsi0", params, changes) + disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "scsi1", params, changes) + disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "scsi2", params, changes) + disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "scsi3", params, changes) + disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "scsi4", params, changes) + disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "scsi5", params, changes) + disks.Disk_6.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_6.convertDataStructure(), vmID, "scsi6", params, changes) + disks.Disk_7.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_7.convertDataStructure(), vmID, "scsi7", params, changes) + disks.Disk_8.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_8.convertDataStructure(), vmID, "scsi8", params, changes) + disks.Disk_9.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_9.convertDataStructure(), vmID, "scsi9", params, changes) + disks.Disk_10.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_10.convertDataStructure(), vmID, "scsi10", params, changes) + disks.Disk_11.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_11.convertDataStructure(), vmID, "scsi11", params, changes) + disks.Disk_12.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_12.convertDataStructure(), vmID, "scsi12", params, changes) + disks.Disk_13.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_13.convertDataStructure(), vmID, "scsi13", params, changes) + disks.Disk_14.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_14.convertDataStructure(), vmID, "scsi14", params, changes) + disks.Disk_15.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_15.convertDataStructure(), vmID, "scsi15", params, changes) + disks.Disk_16.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_16.convertDataStructure(), vmID, "scsi16", params, changes) + disks.Disk_17.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_17.convertDataStructure(), vmID, "scsi17", params, changes) + disks.Disk_18.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_18.convertDataStructure(), vmID, "scsi18", params, changes) + disks.Disk_19.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_19.convertDataStructure(), vmID, "scsi19", params, changes) + disks.Disk_20.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_20.convertDataStructure(), vmID, "scsi20", params, changes) + disks.Disk_21.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_21.convertDataStructure(), vmID, "scsi21", params, changes) + disks.Disk_22.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_22.convertDataStructure(), vmID, "scsi22", params, changes) + disks.Disk_23.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_23.convertDataStructure(), vmID, "scsi23", params, changes) + disks.Disk_24.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_24.convertDataStructure(), vmID, "scsi24", params, changes) + disks.Disk_25.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_25.convertDataStructure(), vmID, "scsi25", params, changes) + disks.Disk_26.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_26.convertDataStructure(), vmID, "scsi26", params, changes) + disks.Disk_27.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_27.convertDataStructure(), vmID, "scsi27", params, changes) + disks.Disk_28.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_28.convertDataStructure(), vmID, "scsi28", params, changes) + disks.Disk_29.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_29.convertDataStructure(), vmID, "scsi29", params, changes) + disks.Disk_30.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_30.convertDataStructure(), vmID, "scsi30", params, changes) } // TODO write test @@ -344,11 +344,6 @@ func (storage QemuScsiStorage) mapToApiValues(vmID uint, create bool) string { return "" } -// TODO write test -func (storage *QemuScsiStorage) markDiskChanges(currentStorage *QemuScsiStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) -} - // TODO write test func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 97feb0e4..f61fab77 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -57,22 +57,22 @@ func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.markDiskChanges(tmpCurrentDisks.Disk_0, vmID, "virtio0", params, changes) - disks.Disk_1.markDiskChanges(tmpCurrentDisks.Disk_1, vmID, "virtio1", params, changes) - disks.Disk_2.markDiskChanges(tmpCurrentDisks.Disk_2, vmID, "virtio2", params, changes) - disks.Disk_3.markDiskChanges(tmpCurrentDisks.Disk_3, vmID, "virtio3", params, changes) - disks.Disk_4.markDiskChanges(tmpCurrentDisks.Disk_4, vmID, "virtio4", params, changes) - disks.Disk_5.markDiskChanges(tmpCurrentDisks.Disk_5, vmID, "virtio5", params, changes) - disks.Disk_6.markDiskChanges(tmpCurrentDisks.Disk_6, vmID, "virtio6", params, changes) - disks.Disk_7.markDiskChanges(tmpCurrentDisks.Disk_7, vmID, "virtio7", params, changes) - disks.Disk_8.markDiskChanges(tmpCurrentDisks.Disk_8, vmID, "virtio8", params, changes) - disks.Disk_9.markDiskChanges(tmpCurrentDisks.Disk_9, vmID, "virtio9", params, changes) - disks.Disk_10.markDiskChanges(tmpCurrentDisks.Disk_10, vmID, "virtio10", params, changes) - disks.Disk_11.markDiskChanges(tmpCurrentDisks.Disk_11, vmID, "virtio11", params, changes) - disks.Disk_12.markDiskChanges(tmpCurrentDisks.Disk_12, vmID, "virtio12", params, changes) - disks.Disk_13.markDiskChanges(tmpCurrentDisks.Disk_13, vmID, "virtio13", params, changes) - disks.Disk_14.markDiskChanges(tmpCurrentDisks.Disk_14, vmID, "virtio14", params, changes) - disks.Disk_15.markDiskChanges(tmpCurrentDisks.Disk_15, vmID, "virtio15", params, changes) + disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "virtio0", params, changes) + disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "virtio1", params, changes) + disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "virtio2", params, changes) + disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "virtio3", params, changes) + disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "virtio4", params, changes) + disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "virtio5", params, changes) + disks.Disk_6.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_6.convertDataStructure(), vmID, "virtio6", params, changes) + disks.Disk_7.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_7.convertDataStructure(), vmID, "virtio7", params, changes) + disks.Disk_8.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_8.convertDataStructure(), vmID, "virtio8", params, changes) + disks.Disk_9.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_9.convertDataStructure(), vmID, "virtio9", params, changes) + disks.Disk_10.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_10.convertDataStructure(), vmID, "virtio10", params, changes) + disks.Disk_11.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_11.convertDataStructure(), vmID, "virtio11", params, changes) + disks.Disk_12.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_12.convertDataStructure(), vmID, "virtio12", params, changes) + disks.Disk_13.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_13.convertDataStructure(), vmID, "virtio13", params, changes) + disks.Disk_14.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_14.convertDataStructure(), vmID, "virtio14", params, changes) + disks.Disk_15.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_15.convertDataStructure(), vmID, "virtio15", params, changes) } // TODO write test @@ -244,11 +244,6 @@ func (storage QemuVirtIOStorage) mapToApiValues(vmID uint, create bool) string { return "" } -// TODO write test -func (storage *QemuVirtIOStorage) markDiskChanges(currentStorage *QemuVirtIOStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { - storage.convertDataStructure().markDiskChanges(currentStorage.convertDataStructure(), vmID, id, params, changes) -} - // TODO write test func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) From de31a18d8ab86abe784a762772d1aca65dc11fbd Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:52:30 +0000 Subject: [PATCH 038/191] feat: make id optional --- proxmox/config_qemu_disk.go | 9 +++++---- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_virtio.go | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index afd4fd2c..0a37e5df 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -132,8 +132,8 @@ type qemuDisk struct { // TODO custom type File string // Only set for Passthrough. Format QemuDiskFormat - Id uint // Only set for Disk - IOThread bool // Only set for scsi,virtio + Id *uint // Only set for Disk + IOThread bool // Only set for scsi,virtio Number uint ReadOnly bool // Only set for scsi,virtio Replicate bool @@ -241,7 +241,8 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { tmp := strings.Split(idAndFormat[0], "-") if len(tmp) > 1 { tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) - disk.Id = uint(tmpId) + idPointer := uint(tmpId) + disk.Id = &idPointer } } } @@ -471,7 +472,7 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update - if storage.Disk.Id == 0 { + if storage.Disk.Id == nil { storage.Disk.Id = currentStorage.Disk.Id } if storage.Disk.Storage != currentStorage.Disk.Storage { diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 9e1aefad..fee64099 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -7,7 +7,7 @@ type QemuIdeDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Id uint `json:"id,omitempty"` + Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index bb640026..e9521bc8 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -7,7 +7,7 @@ type QemuSataDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Id uint `json:"id,omitempty"` + Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size,omitempty"` diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index af094d72..4a0b28f7 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -7,7 +7,7 @@ type QemuScsiDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Id uint `json:"id,omitempty"` + Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index f61fab77..c385c691 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -6,7 +6,7 @@ type QemuVirtIODisk struct { Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` - Id uint `json:"id,omitempty"` + Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` Replicate bool `json:"replicate,omitempty"` From b594866e86b85b148a0bd2a2c5600905d0c4290a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 12:50:18 +0000 Subject: [PATCH 039/191] feat: add disk resizing --- proxmox/config_qemu_disk.go | 38 ++++++++++++++++++++++++------ proxmox/config_qemu_disk_ide.go | 3 +++ proxmox/config_qemu_disk_sata.go | 3 +++ proxmox/config_qemu_disk_scsi.go | 3 +++ proxmox/config_qemu_disk_virtio.go | 3 +++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 0a37e5df..b4204e91 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -130,10 +130,10 @@ type qemuDisk struct { Discard bool EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type - File string // Only set for Passthrough. - Format QemuDiskFormat - Id *uint // Only set for Disk - IOThread bool // Only set for scsi,virtio + File string // Only set for Passthrough. + Format *QemuDiskFormat // Only set for Disk + Id *uint // Only set for Disk + IOThread bool // Only set for scsi,virtio Number uint ReadOnly bool // Only set for scsi,virtio Replicate bool @@ -150,7 +150,9 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { if create { settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) } else { - settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) + // test:100/vm-100-disk-0.raw + tmpId := strconv.Itoa(int(vmID)) + settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(*disk.Id)) + "." + string(*disk.Format) } } @@ -237,7 +239,8 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(diskAndNumberAndFormat) == 2 { idAndFormat := strings.Split(diskAndNumberAndFormat[1], ".") if len(idAndFormat) == 2 { - disk.Format = QemuDiskFormat(idAndFormat[1]) + tmpFormat := QemuDiskFormat(idAndFormat[1]) + disk.Format = &tmpFormat tmp := strings.Split(idAndFormat[0], "-") if len(tmp) > 1 { tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) @@ -419,6 +422,17 @@ func (serial QemuDiskSerial) Validate() error { return nil } +type qemuDiskResize struct { + Id string + SizeInGigaBytes uint +} + +// Increase the disk size to the specified amount in gigabytes +// Decrease of disk size is not permitted. +func (disk qemuDiskResize) resize(vmr *VmRef, client *Client) (exitStatus string, err error) { + return client.PutWithTask(map[string]interface{}{"disk": disk.Id, "size": strconv.Itoa(int(disk.SizeInGigaBytes)) + "G"}, fmt.Sprintf("/nodes/%s/%s/%d/resize", vmr.node, vmr.vmType, vmr.vmId)) +} + type qemuDiskShort struct { Storage string Id string @@ -472,9 +486,18 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update + if storage.Disk.Size > currentStorage.Disk.Size { + changes.Resize = append(changes.Resize, qemuDiskResize{ + Id: id, + SizeInGigaBytes: storage.Disk.Size, + }) + } if storage.Disk.Id == nil { storage.Disk.Id = currentStorage.Disk.Id } + if storage.Disk.Format == nil { + storage.Disk.Format = currentStorage.Disk.Format + } if storage.Disk.Storage != currentStorage.Disk.Storage { changes.Move = append(changes.Move, qemuDiskShort{ Id: id, @@ -563,6 +586,7 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { } type qemuUpdateChanges struct { - Move []qemuDiskShort Delete string + Move []qemuDiskShort + Resize []qemuDiskResize } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index fee64099..0bd82dc0 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -7,6 +7,7 @@ type QemuIdeDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Format *QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` @@ -130,6 +131,7 @@ func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { Cache: storage.Disk.Cache, Discard: storage.Disk.Discard, EmulateSSD: storage.Disk.EmulateSSD, + Format: storage.Disk.Format, Id: storage.Disk.Id, Replicate: storage.Disk.Replicate, Serial: storage.Disk.Serial, @@ -194,6 +196,7 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, Id: tmpDisk.Id, Replicate: tmpDisk.Replicate, Serial: tmpDisk.Serial, diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index e9521bc8..0cadba80 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -7,6 +7,7 @@ type QemuSataDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Format *QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` @@ -142,6 +143,7 @@ func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { Cache: storage.Disk.Cache, Discard: storage.Disk.Discard, EmulateSSD: storage.Disk.EmulateSSD, + Format: storage.Disk.Format, Id: storage.Disk.Id, Replicate: storage.Disk.Replicate, Serial: storage.Disk.Serial, @@ -206,6 +208,7 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, Id: tmpDisk.Id, Replicate: tmpDisk.Replicate, Serial: tmpDisk.Serial, diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 4a0b28f7..b98c67f3 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -7,6 +7,7 @@ type QemuScsiDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` + Format *QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` @@ -300,6 +301,7 @@ func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { Cache: storage.Disk.Cache, Discard: storage.Disk.Discard, EmulateSSD: storage.Disk.EmulateSSD, + Format: storage.Disk.Format, Id: storage.Disk.Id, IOThread: storage.Disk.IOThread, ReadOnly: storage.Disk.ReadOnly, @@ -368,6 +370,7 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, Id: tmpDisk.Id, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index c385c691..96f86a12 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -6,6 +6,7 @@ type QemuVirtIODisk struct { Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` + Format *QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` @@ -202,6 +203,7 @@ func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { Bandwidth: storage.Disk.Bandwidth, Cache: storage.Disk.Cache, Discard: storage.Disk.Discard, + Format: storage.Disk.Format, Id: storage.Disk.Id, IOThread: storage.Disk.IOThread, ReadOnly: storage.Disk.ReadOnly, @@ -267,6 +269,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { Bandwidth: tmpDisk.Bandwidth, Cache: tmpDisk.Cache, Discard: tmpDisk.Discard, + Format: tmpDisk.Format, Id: tmpDisk.Id, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, From 1665b1b5ce40038961d995b4a62542a2d8b30627 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 12:51:48 +0000 Subject: [PATCH 040/191] Commit missing changes --- proxmox/config_qemu.go | 69 ++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 9b3e57c4..d9c74425 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -3,6 +3,7 @@ package proxmox import ( "bytes" "encoding/json" + "errors" "fmt" "log" "math/rand" @@ -86,7 +87,11 @@ type ConfigQemu struct { // CreateVm - Tell Proxmox API to make the VM func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { - params, _, err := config.mapToApiValues(ConfigQemu{}, vmr) + err = config.setVmr(vmr) + if err != nil { + return + } + params, _, err := config.mapToApiValues(ConfigQemu{}) if err != nil { return } @@ -104,16 +109,15 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { return } -func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { - - vmr.SetVmType("qemu") +func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { var itemsToDelete string - params = map[string]interface{}{ - "vmid": vmr.vmId, - } + params = map[string]interface{}{} + if config.VmID != 0 { + params["vmid"] = config.VmID + } if config.Args != "" { params["args"] = config.Args } @@ -177,8 +181,8 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (p if config.QemuOs != "" { params["ostype"] = config.QemuOs } - if vmr.pool != "" { - params["pool"] = vmr.pool + if config.Pool != "" { + params["pool"] = config.Pool } if config.Scsihw != "" { params["scsihw"] = config.Scsihw @@ -208,14 +212,14 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (p // Disks if currentConfig.Disks != nil { if config.Disks != nil { - markedDisks = config.Disks.markDiskChanges(*currentConfig.Disks, params) + markedDisks = config.Disks.markDiskChanges(*currentConfig.Disks, uint(config.VmID), params) } if markedDisks.Delete != "" { itemsToDelete = AddToList(itemsToDelete, markedDisks.Delete) } } else { if config.Disks != nil { - config.Disks.mapToApiValues(params) + config.Disks.mapToApiValues(uint(config.VmID), params) } } @@ -223,7 +227,7 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu, vmr *VmRef) (p config.CreateQemuEfiParams(params) // Create networks config. - config.CreateQemuNetworksParams(vmr.vmId, params) + config.CreateQemuNetworksParams(params) // Create vga config. vgaParam := QemuDeviceParam{} @@ -258,16 +262,40 @@ func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { return newConfig.UpdateAdvanced(currentConfig, vmr, client) } +func (config *ConfigQemu) setVmr(vmr *VmRef) error { + if config == nil { + return errors.New("config may not be nil") + } + if vmr == nil { + return errors.New("vm reference may not be nil") + } + vmr.SetVmType("qemu") + config.VmID = vmr.vmId + return nil +} + func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { - params, markedDisks, err := newConfig.mapToApiValues(*currentConfig, vmr) + err = newConfig.setVmr(vmr) + if err != nil { + return + } + params, markedDisks, err := newConfig.mapToApiValues(*currentConfig) if err != nil { return } - for _, e := range markedDisks.Move { - _, err = client.MoveQemuDisk(vmr, e.Id, e.Storage) - if err != nil { - return + if markedDisks != nil { + for _, e := range markedDisks.Move { + _, err = client.MoveQemuDisk(vmr, e.Id, e.Storage) + if err != nil { + return + } + } + for _, e := range markedDisks.Resize { + _, err = e.resize(vmr, client) + if err != nil { + return + } } } @@ -463,7 +491,8 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { } // Create networks config. - config.CreateQemuNetworksParams(vmr.vmId, configParams) + config.VmID = vmr.vmId + config.CreateQemuNetworksParams(configParams) // Create vga config. vgaParam := QemuDeviceParam{} @@ -1158,7 +1187,7 @@ func FormatUsbParam(usb QemuDevice) string { } // Create parameters for each Nic device. -func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interface{}) { +func (c ConfigQemu) CreateQemuNetworksParams(params map[string]interface{}) { // For new style with multi net device. for nicID, nicConfMap := range c.QemuNetworks { @@ -1184,7 +1213,7 @@ func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interfa // Generate deterministic Mac based on VmID and NicID // Assume that rare VM has more than 32 nics macaddr := make(net.HardwareAddr, 6) - pairing := vmID<<5 | nicID + pairing := c.VmID<<5 | nicID // Linux MAC vendor - 00:18:59 macaddr[0] = 0x00 macaddr[1] = 0x18 From a05ef20771b8755a48d8686fb0d8cf856989ffe9 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 12:52:04 +0000 Subject: [PATCH 041/191] Add TODO --- proxmox/client.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proxmox/client.go b/proxmox/client.go index b2079ccd..dffd7b7b 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -736,6 +736,7 @@ func (c *Client) MigrateNode(vmr *VmRef, newTargetNode string, online bool) (exi } // ResizeQemuDisk allows the caller to increase the size of a disk by the indicated number of gigabytes +// TODO Deprecate once LXC is able to resize disk by itself (qemu can already do this) func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitStatus interface{}, err error) { size := fmt.Sprintf("+%dG", moreSizeGB) return c.ResizeQemuDiskRaw(vmr, disk, size) @@ -746,6 +747,7 @@ func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitSt // your desired size with a '+' character it will ADD size to the disk. If you just specify the size by // itself it will do an absolute resizing to the specified size. Permitted suffixes are K, M, G, T // to indicate order of magnitude (kilobyte, megabyte, etc). Decrease of disk size is not permitted. +// TODO Deprecate once LXC is able to resize disk by itself (qemu can already do this) func (c *Client) ResizeQemuDiskRaw(vmr *VmRef, disk string, size string) (exitStatus interface{}, err error) { // PUT //disk:virtio0 From bd13540819136417063562da0048d2bde8265d2c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 14:35:40 +0000 Subject: [PATCH 042/191] refactor: remove dead code --- proxmox/config_qemu_disk_ide.go | 52 ++------------------------- proxmox/config_qemu_disk_sata.go | 52 ++------------------------- proxmox/config_qemu_disk_scsi.go | 56 ++---------------------------- proxmox/config_qemu_disk_virtio.go | 52 ++------------------------- 4 files changed, 8 insertions(+), 204 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 0bd82dc0..06292bab 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -15,23 +15,6 @@ type QemuIdeDisk struct { Storage string `json:"storage,omitempty"` } -// TODO write test -func (disk QemuIdeDisk) mapToApiValues(vmID uint, create bool) string { - return qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - EmulateSSD: disk.EmulateSSD, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: ide, - }.mapToApiValues(vmID, create) -} - type QemuIdeDisks struct { Disk_0 *QemuIdeStorage `json:"0,omitempty"` Disk_1 *QemuIdeStorage `json:"1,omitempty"` @@ -90,22 +73,6 @@ type QemuIdePassthrough struct { Size uint //size is only returned and setting it has no effect } -// TODO write test -func (passthrough QemuIdePassthrough) mapToApiValues() string { - return qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: ide, - }.mapToApiValues(0, false) -} - type QemuIdeStorage struct { CdRom *QemuCdRom `json:"cdrom,omitempty"` CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` @@ -137,6 +104,7 @@ func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { Serial: storage.Disk.Serial, Size: storage.Disk.Size, Storage: storage.Disk.Storage, + Type: ide, } } if storage.Passthrough != nil { @@ -150,28 +118,12 @@ func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { File: storage.Passthrough.File, Replicate: storage.Passthrough.Replicate, Serial: storage.Passthrough.Serial, + Type: ide, } } return &generalizedStorage } -// TODO write test -func (storage QemuIdeStorage) mapToApiValues(vmID uint, create bool) string { - if storage.Disk != nil { - return storage.Disk.mapToApiValues(vmID, create) - } - if storage.CdRom != nil { - return storage.CdRom.mapToApiValues() - } - if storage.CloudInit != nil { - return storage.CloudInit.mapToApiValues() - } - if storage.Passthrough != nil { - return storage.Passthrough.mapToApiValues() - } - return "" -} - // TODO write test func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 0cadba80..dfd50c70 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -15,23 +15,6 @@ type QemuSataDisk struct { Storage string `json:"storage,omitempty"` } -// TODO write test -func (disk QemuSataDisk) mapToApiValues(vmID uint, create bool) string { - return qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - EmulateSSD: disk.EmulateSSD, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: sata, - }.mapToApiValues(vmID, create) -} - type QemuSataDisks struct { Disk_0 *QemuSataStorage `json:"0,omitempty"` Disk_1 *QemuSataStorage `json:"1,omitempty"` @@ -102,22 +85,6 @@ type QemuSataPassthrough struct { Size uint //size is only returned and setting it has no effect } -// TODO write test -func (passthrough QemuSataPassthrough) mapToApiValues() string { - return qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: sata, - }.mapToApiValues(0, false) -} - type QemuSataStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -149,6 +116,7 @@ func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { Serial: storage.Disk.Serial, Size: storage.Disk.Size, Storage: storage.Disk.Storage, + Type: sata, } } if storage.Passthrough != nil { @@ -162,28 +130,12 @@ func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { File: storage.Passthrough.File, Replicate: storage.Passthrough.Replicate, Serial: storage.Passthrough.Serial, + Type: sata, } } return &generalizedStorage } -// TODO write test -func (storage QemuSataStorage) mapToApiValues(vmID uint, create bool) string { - if storage.Disk != nil { - return storage.Disk.mapToApiValues(vmID, create) - } - if storage.CdRom != nil { - return storage.CdRom.mapToApiValues() - } - if storage.CloudInit != nil { - return storage.CloudInit.mapToApiValues() - } - if storage.Passthrough != nil { - return storage.Passthrough.mapToApiValues() - } - return "" -} - // TODO write test func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index b98c67f3..2c1c0a8d 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -17,25 +17,6 @@ type QemuScsiDisk struct { Storage string `json:"storage,omitempty"` } -// TODO write test -func (disk QemuScsiDisk) mapToApiValues(vmID uint, create bool) string { - return qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - EmulateSSD: disk.EmulateSSD, - IOThread: disk.IOThread, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: scsi, - }.mapToApiValues(vmID, create) -} - type QemuScsiDisks struct { Disk_0 *QemuScsiStorage `json:"0,omitempty"` Disk_1 *QemuScsiStorage `json:"1,omitempty"` @@ -258,24 +239,6 @@ type QemuScsiPassthrough struct { Size uint //size is only returned and setting it has no effect } -// TODO write test -func (passthrough QemuScsiPassthrough) mapToApiValues() string { - return qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - IOThread: passthrough.IOThread, - ReadOnly: passthrough.ReadOnly, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: scsi, - }.mapToApiValues(0, false) -} - type QemuScsiStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -309,6 +272,7 @@ func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { Serial: storage.Disk.Serial, Size: storage.Disk.Size, Storage: storage.Disk.Storage, + Type: scsi, } } if storage.Passthrough != nil { @@ -324,28 +288,12 @@ func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { ReadOnly: storage.Passthrough.ReadOnly, Replicate: storage.Passthrough.Replicate, Serial: storage.Passthrough.Serial, + Type: scsi, } } return &generalizedStorage } -// TODO write test -func (storage QemuScsiStorage) mapToApiValues(vmID uint, create bool) string { - if storage.Disk != nil { - return storage.Disk.mapToApiValues(vmID, create) - } - if storage.CdRom != nil { - return storage.CdRom.mapToApiValues() - } - if storage.CloudInit != nil { - return storage.CloudInit.mapToApiValues() - } - if storage.Passthrough != nil { - return storage.Passthrough.mapToApiValues() - } - return "" -} - // TODO write test func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 96f86a12..9f08493e 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -16,23 +16,6 @@ type QemuVirtIODisk struct { Storage string `json:"storage,omitempty"` } -// TODO write test -func (disk QemuVirtIODisk) mapToApiValues(vmID uint, create bool) string { - return qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - IOThread: disk.IOThread, - ReadOnly: disk.ReadOnly, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: virtIO, - }.mapToApiValues(vmID, create) -} - type QemuVirtIODisks struct { Disk_0 *QemuVirtIOStorage `json:"0,omitempty"` Disk_1 *QemuVirtIOStorage `json:"1,omitempty"` @@ -163,22 +146,6 @@ type QemuVirtIOPassthrough struct { Size uint //size is only returned and setting it has no effect } -// TODO write test -func (passthrough QemuVirtIOPassthrough) mapToApiValues() string { - return qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - File: passthrough.File, - IOThread: passthrough.IOThread, - ReadOnly: passthrough.ReadOnly, - Serial: passthrough.Serial, - Type: scsi, - }.mapToApiValues(0, false) -} - type QemuVirtIOStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -211,6 +178,7 @@ func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { Serial: storage.Disk.Serial, Size: storage.Disk.Size, Storage: storage.Disk.Storage, + Type: virtIO, } } if storage.Passthrough != nil { @@ -224,28 +192,12 @@ func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { IOThread: storage.Passthrough.IOThread, ReadOnly: storage.Passthrough.ReadOnly, Serial: storage.Passthrough.Serial, + Type: virtIO, } } return &generalizedStorage } -// TODO write test -func (storage QemuVirtIOStorage) mapToApiValues(vmID uint, create bool) string { - if storage.Disk != nil { - return storage.Disk.mapToApiValues(vmID, create) - } - if storage.CdRom != nil { - return storage.CdRom.mapToApiValues() - } - if storage.CloudInit != nil { - return storage.CloudInit.mapToApiValues() - } - if storage.Passthrough != nil { - return storage.Passthrough.mapToApiValues() - } - return "" -} - // TODO write test func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) From 56949b20d8742eb94e87ec8dd1efc25ea1e2b5b2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 15:18:03 +0000 Subject: [PATCH 043/191] refactor: put in alphabetical order --- proxmox/config_qemu_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index b4204e91..621a7335 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -106,8 +106,8 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { } type QemuCloudInitDisk struct { - Storage string FileType string + Storage string } // TODO write test From 343c2c854be47509a61495a37df5979969f3b872 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 15:59:07 +0000 Subject: [PATCH 044/191] fix: panic --- proxmox/config_qemu.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index d9c74425..9ff15b10 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -213,9 +213,10 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[st if currentConfig.Disks != nil { if config.Disks != nil { markedDisks = config.Disks.markDiskChanges(*currentConfig.Disks, uint(config.VmID), params) - } - if markedDisks.Delete != "" { - itemsToDelete = AddToList(itemsToDelete, markedDisks.Delete) + if markedDisks.Delete != "" { + itemsToDelete = AddToList(itemsToDelete, markedDisks.Delete) + markedDisks.Delete = "" + } } } else { if config.Disks != nil { From a988d64fdc76219f547c79258fa1976e038c1660 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:07:49 +0000 Subject: [PATCH 045/191] fix: bugs caused by conditionals --- proxmox/config_qemu_disk.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 621a7335..6ac8ddd5 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -463,7 +463,7 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui // Create or Update params[id] = storage.CdRom.mapToApiValues() return - } else if currentStorage != nil && currentStorage.CdRom != nil { + } else if currentStorage != nil && currentStorage.CdRom != nil && storage.CloudInit == nil && storage.Disk == nil && storage.Passthrough == nil { // Delete changes.Delete = AddToList(changes.Delete, id) return @@ -473,7 +473,7 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui // Create or Update params[id] = storage.CloudInit.mapToApiValues() return - } else if currentStorage != nil && currentStorage.CloudInit != nil { + } else if currentStorage != nil && currentStorage.CloudInit != nil && storage.Disk == nil && storage.Passthrough == nil { // Delete changes.Delete = AddToList(changes.Delete, id) return @@ -483,6 +483,7 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui if currentStorage == nil || currentStorage.Disk == nil { // Create params[id] = storage.Disk.mapToApiValues(vmID, true) + return } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update @@ -507,12 +508,12 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui params[id] = storage.Disk.mapToApiValues(vmID, false) } else { // Delete and Create - changes.Delete = AddToList(changes.Delete, id) + // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. params[id] = storage.Disk.mapToApiValues(vmID, true) } + return } - return - } else if currentStorage != nil && currentStorage.Disk != nil { + } else if currentStorage != nil && currentStorage.Disk != nil && storage.Passthrough == nil { // Delete changes.Delete = AddToList(changes.Delete, id) return @@ -542,16 +543,16 @@ type QemuStorages struct { func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID uint, params map[string]interface{}) *qemuUpdateChanges { changes := &qemuUpdateChanges{} - if currentStorages.Ide != nil { + if storages.Ide != nil { storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, changes) } - if currentStorages.Sata != nil { + if storages.Sata != nil { storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, changes) } - if currentStorages.Scsi != nil { + if storages.Scsi != nil { storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, changes) } - if currentStorages.VirtIO != nil { + if storages.VirtIO != nil { storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, changes) } return changes From 90e6dba2013de3aeb4db8395daa3fad371b9d621 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:18:40 +0000 Subject: [PATCH 046/191] feat: add new Iso setting --- proxmox/config_qemu.go | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 9ff15b10..4b21e76d 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -54,16 +54,17 @@ type ConfigQemu struct { Hookscript string `json:"hookscript,omitempty"` Hotplug string `json:"hotplug,omitempty"` // TODO should be a struct Ipconfig IpconfigMap `json:"ipconfig,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + Iso *IsoFile `json:"iso,omitempty"` // Same as Disks.Ide.Disk_2.CdRom.Iso Machine string `json:"machine,omitempty"` // TODO should be custom type with enum Memory int `json:"memory,omitempty"` // TODO should be uint Name string `json:"name,omitempty"` // TODO should be custom type as there are character and length limitations Nameserver string `json:"nameserver,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) Onboot *bool `json:"onboot,omitempty"` - Pool string `json:"pool,omitempty"` // TODO should be custom type as there are character and length limitations - QemuCores int `json:"cores,omitempty"` // TODO should be uint - QemuCpu string `json:"cpu,omitempty"` // TODO should be custom type with enum - QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead - QemuIso string `json:"iso,omitempty"` // TODO should be a struct + Pool string `json:"pool,omitempty"` // TODO should be custom type as there are character and length limitations + QemuCores int `json:"cores,omitempty"` // TODO should be uint + QemuCpu string `json:"cpu,omitempty"` // TODO should be custom type with enum + QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead + QemuIso string `json:"qemuiso,omitempty"` // DEPRECATED use Iso *IsoFile instead QemuKVM *bool `json:"kvm,omitempty"` QemuNetworks QemuDevices `json:"network,omitempty"` // TODO should be a struct QemuNuma *bool `json:"numa,omitempty"` @@ -209,6 +210,20 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[st params["vcpus"] = config.QemuVcpus } + if config.Iso != nil { + if config.Disks == nil { + config.Disks = &QemuStorages{} + } + if config.Disks.Ide == nil { + config.Disks.Ide = &QemuIdeDisks{} + } + if config.Disks.Ide.Disk_2 == nil { + config.Disks.Ide.Disk_2 = &QemuIdeStorage{} + } + if config.Disks.Ide.Disk_2.CdRom == nil { + config.Disks.Ide.Disk_2.CdRom = &QemuCdRom{Iso: config.Iso} + } + } // Disks if currentConfig.Disks != nil { if config.Disks != nil { @@ -751,11 +766,6 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e config.QemuVcpus = int(vcpus) } - if vmConfig["ide2"] != nil { - isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string)) - config.QemuIso = isoMatch[1] - } - // Add Cloud-Init options if _, isSet := vmConfig["ciuser"]; isSet { config.CIuser = vmConfig["ciuser"].(string) @@ -793,6 +803,10 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e config.Disks = QemuStorages{}.mapToStruct(vmConfig) + if config.Disks != nil && config.Disks.Ide != nil && config.Disks.Ide.Disk_2 != nil && config.Disks.Ide.Disk_2.CdRom != nil { + config.Iso = config.Disks.Ide.Disk_2.CdRom.Iso + } + // Add unused disks // unused0:local:100/vm-100-disk-1.qcow2 unusedDiskNames := []string{} From c9718e1e1f5b13eb4cac9c210b9145975d402eec Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:21:29 +0000 Subject: [PATCH 047/191] refactor: change post to put --- proxmox/config_qemu.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 4b21e76d..122015e9 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -317,7 +317,7 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef // TODO Migrate VM - _, err = client.PostWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") + _, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") if err != nil { return } From 2ab981216ffb70fe8cd0b95793e0db5f7ac6fc39 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:35:15 +0000 Subject: [PATCH 048/191] feat: logic for node migration --- proxmox/config_qemu.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 122015e9..a8952eb6 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -59,6 +59,7 @@ type ConfigQemu struct { Memory int `json:"memory,omitempty"` // TODO should be uint Name string `json:"name,omitempty"` // TODO should be custom type as there are character and length limitations Nameserver string `json:"nameserver,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) + Node string `json:"node,omitempty"` Onboot *bool `json:"onboot,omitempty"` Pool string `json:"pool,omitempty"` // TODO should be custom type as there are character and length limitations QemuCores int `json:"cores,omitempty"` // TODO should be uint @@ -315,7 +316,14 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef } } - // TODO Migrate VM + if newConfig.Node != currentConfig.Node { + vmr.SetNode(currentConfig.Node) + _, err = client.MigrateNode(vmr, newConfig.Node, true) + if err != nil { + return + } + vmr.SetNode(newConfig.Node) + } _, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") if err != nil { From c0f97853fbc42a763e7bcc6df811772f1e6d0287 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 21:31:24 +0000 Subject: [PATCH 049/191] refactor: move converting from api to struct into its own function --- proxmox/config_qemu.go | 709 ++++++++++++++++++++--------------------- 1 file changed, 345 insertions(+), 364 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index a8952eb6..602bacf8 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -271,6 +271,348 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[st return } +func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu, err error) { + // vmConfig Sample: map[ cpu:host + // net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0 + // ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048 + // smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1 + // name:terraform-ubuntu1404-template bootdisk:virtio0 + // virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G + // description:Base image + // cores:2 ostype:l26 + + config = &ConfigQemu{ + EFIDisk: QemuDevice{}, + QemuDisks: QemuDevices{}, + QemuUnusedDisks: QemuDevices{}, + QemuVga: QemuDevice{}, + QemuNetworks: QemuDevices{}, + QemuSerials: QemuDevices{}, + QemuPCIDevices: QemuDevices{}, + QemuUsbs: QemuDevices{}, + Ipconfig: IpconfigMap{}, + } + + if _, isSet := params["agent"]; isSet { + switch params["agent"].(type) { + case float64: + config.Agent = int(params["agent"].(float64)) + case string: + AgentConfList := strings.Split(params["agent"].(string), ",") + config.Agent, _ = strconv.Atoi(AgentConfList[0]) + } + } + if _, isSet := params["args"]; isSet { + config.Args = strings.TrimSpace(params["args"].(string)) + } + if _, isSet := params["balloon"]; isSet { + balloon := int(params["balloon"].(float64)) + if balloon > 0 { + config.Balloon = balloon + } + } + //boot by default from hard disk (c), CD-ROM (d), network (n). + if _, isSet := params["boot"]; isSet { + config.Boot = params["boot"].(string) + } else { + config.Boot = "cdn" + } + if _, isSet := params["bootdisk"]; isSet { + config.BootDisk = params["bootdisk"].(string) + } + if _, isSet := params["bios"]; isSet { + config.Bios = params["bios"].(string) + } else { + config.Bios = "seabios" + } + if _, isSet := params["cicustom"]; isSet { + config.CIcustom = params["cicustom"].(string) + } + if _, isSet := params["cipassword"]; isSet { + config.CIpassword = params["cipassword"].(string) + } + if _, isSet := params["ciuser"]; isSet { + config.CIuser = params["ciuser"].(string) + } + if _, isSet := params["description"]; isSet { + config.Description = strings.TrimSpace(params["description"].(string)) + } + //Can be network,disk,cpu,memory,usb + if _, isSet := params["hotplug"]; isSet { + config.Hotplug = params["hotplug"].(string) + } else { + config.Hotplug = "network,disk,usb" + } + if _, isSet := params["hookscript"]; isSet { + config.Hookscript = params["hookscript"].(string) + } + if _, isSet := params["memory"]; isSet { + config.Memory = int(params["memory"].(float64)) + } + if _, isSet := params["name"]; isSet { + config.Name = params["name"].(string) + } + if _, isSet := params["nameserver"]; isSet { + config.Nameserver = params["nameserver"].(string) + } + if _, isSet := params["onboot"]; isSet { + config.Onboot = PointerBool(Itob(int(params["onboot"].(float64)))) + } else { + config.Onboot = PointerBool(true) + } + if _, isSet := params["cores"]; isSet { + config.QemuCores = int(params["cores"].(float64)) + } else { + config.QemuCores = 1 + } + if _, isSet := params["cpu"]; isSet { + config.QemuCpu = params["cpu"].(string) + } else { + config.QemuCpu = "host" + } + if _, isSet := params["kvm"]; isSet { + config.QemuKVM = PointerBool(Itob(int(params["kvm"].(float64)))) + } else { + config.QemuKVM = PointerBool(true) + } + if _, isSet := params["numa"]; isSet { + config.QemuNuma = PointerBool(Itob(int(params["numa"].(float64)))) + } + if _, isSet := params["ostype"]; isSet { + config.QemuOs = params["ostype"].(string) + } else { + config.QemuOs = "other" + } + if _, isSet := params["sockets"]; isSet { + config.QemuSockets = int(params["sockets"].(float64)) + } else { + config.QemuSockets = 1 + } + if _, isSet := params["vcpus"]; isSet { + vCpu := int(params["vcpus"].(float64)) + if vCpu > 0 { + config.QemuVcpus = vCpu + } + } + if _, isSet := params["scsihw"]; isSet { + config.Scsihw = params["scsihw"].(string) + } else { + config.Scsihw = "lsi" + } + if _, isSet := params["searchdomain"]; isSet { + config.Searchdomain = params["searchdomain"].(string) + } + if _, isSet := params["sshkeys"]; isSet { + config.Sshkeys, _ = url.PathUnescape(params["sshkeys"].(string)) + } + if _, isSet := params["startup"]; isSet { + config.Startup = params["startup"].(string) + } + if _, isSet := params["tablet"]; isSet { + config.Tablet = PointerBool(Itob(int(params["tablet"].(float64)))) + } else { + config.Tablet = PointerBool(true) + } + if _, isSet := params["tags"]; isSet { + config.Tags = strings.TrimSpace(params["tags"].(string)) + } + + ipconfigNames := []string{} + + for k := range params { + if ipconfigName := rxIpconfigName.FindStringSubmatch(k); len(ipconfigName) > 0 { + ipconfigNames = append(ipconfigNames, ipconfigName[0]) + } + } + + for _, ipconfigName := range ipconfigNames { + ipConfStr := params[ipconfigName] + id := rxDeviceID.FindStringSubmatch(ipconfigName) + ipconfigID, _ := strconv.Atoi(id[0]) + config.Ipconfig[ipconfigID] = ipConfStr + } + + config.Disks = QemuStorages{}.mapToStruct(params) + + if config.Disks != nil && config.Disks.Ide != nil && config.Disks.Ide.Disk_2 != nil && config.Disks.Ide.Disk_2.CdRom != nil { + config.Iso = config.Disks.Ide.Disk_2.CdRom.Iso + } + + // Add unused disks + // unused0:local:100/vm-100-disk-1.qcow2 + unusedDiskNames := []string{} + for k := range params { + // look for entries from the config in the format "unusedX:" where X is an integer + if unusedDiskName := rxUnusedDiskName.FindStringSubmatch(k); len(unusedDiskName) > 0 { + unusedDiskNames = append(unusedDiskNames, unusedDiskName[0]) + } + } + // if len(unusedDiskNames) > 0 { + // log.Printf("[DEBUG] unusedDiskNames: %v", unusedDiskNames) + // } + + for _, unusedDiskName := range unusedDiskNames { + unusedDiskConfStr := params[unusedDiskName].(string) + finalDiskConfMap := QemuDevice{} + + // parse "unused0" to get the id '0' as an int + id := rxDeviceID.FindStringSubmatch(unusedDiskName) + diskID, err := strconv.Atoi(id[0]) + if err != nil { + return nil, fmt.Errorf(fmt.Sprintf("Unable to parse unused disk id from input string '%v' tried to convert '%v' to integer.", unusedDiskName, diskID)) + } + finalDiskConfMap["slot"] = diskID + + // parse the attributes from the unused disk + // extract the storage and file path from the unused disk entry + parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") + storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") + finalDiskConfMap["storage"] = storageName + finalDiskConfMap["file"] = fileName + + config.QemuUnusedDisks[diskID] = finalDiskConfMap + } + + //Display + if vga, isSet := params["vga"]; isSet { + vgaList := strings.Split(vga.(string), ",") + vgaMap := QemuDevice{} + + vgaMap.readDeviceConfig(vgaList) + if len(vgaMap) > 0 { + config.QemuVga = vgaMap + } + } + + // Add networks. + nicNames := []string{} + + for k := range params { + if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 { + nicNames = append(nicNames, nicName[0]) + } + } + + for _, nicName := range nicNames { + nicConfStr := params[nicName] + nicConfList := strings.Split(nicConfStr.(string), ",") + + id := rxDeviceID.FindStringSubmatch(nicName) + nicID, _ := strconv.Atoi(id[0]) + model, macaddr := ParseSubConf(nicConfList[0], "=") + + // Add model and MAC address. + nicConfMap := QemuDevice{ + "id": nicID, + "model": model, + "macaddr": macaddr, + } + + // Add rest of device config. + nicConfMap.readDeviceConfig(nicConfList[1:]) + switch nicConfMap["firewall"] { + case 1: + nicConfMap["firewall"] = true + case 0: + nicConfMap["firewall"] = false + } + switch nicConfMap["link_down"] { + case 1: + nicConfMap["link_down"] = true + case 0: + nicConfMap["link_down"] = false + } + + // And device config to networks. + if len(nicConfMap) > 0 { + config.QemuNetworks[nicID] = nicConfMap + } + } + + // Add serials + serialNames := []string{} + + for k := range params { + if serialName := rxSerialName.FindStringSubmatch(k); len(serialName) > 0 { + serialNames = append(serialNames, serialName[0]) + } + } + + for _, serialName := range serialNames { + id := rxDeviceID.FindStringSubmatch(serialName) + serialID, _ := strconv.Atoi(id[0]) + + serialConfMap := QemuDevice{ + "id": serialID, + "type": params[serialName], + } + + // And device config to serials map. + if len(serialConfMap) > 0 { + config.QemuSerials[serialID] = serialConfMap + } + } + + // Add usbs + usbNames := []string{} + + for k := range params { + if usbName := rxUsbName.FindStringSubmatch(k); len(usbName) > 0 { + usbNames = append(usbNames, usbName[0]) + } + } + + for _, usbName := range usbNames { + usbConfStr := params[usbName] + usbConfList := strings.Split(usbConfStr.(string), ",") + id := rxDeviceID.FindStringSubmatch(usbName) + usbID, _ := strconv.Atoi(id[0]) + _, host := ParseSubConf(usbConfList[0], "=") + + usbConfMap := QemuDevice{ + "id": usbID, + "host": host, + } + + usbConfMap.readDeviceConfig(usbConfList[1:]) + if usbConfMap["usb3"] == 1 { + usbConfMap["usb3"] = true + } + + // And device config to usbs map. + if len(usbConfMap) > 0 { + config.QemuUsbs[usbID] = usbConfMap + } + } + + // hostpci + hostPCInames := []string{} + + for k := range params { + if hostPCIname := rxPCIName.FindStringSubmatch(k); len(hostPCIname) > 0 { + hostPCInames = append(hostPCInames, hostPCIname[0]) + } + } + + for _, hostPCIname := range hostPCInames { + hostPCIConfStr := params[hostPCIname] + hostPCIConfList := strings.Split(hostPCIConfStr.(string), ",") + id := rxPCIName.FindStringSubmatch(hostPCIname) + hostPCIID, _ := strconv.Atoi(id[0]) + hostPCIConfMap := QemuDevice{ + "id": hostPCIID, + } + hostPCIConfMap.readDeviceConfig(hostPCIConfList) + // And device config to usbs map. + if len(hostPCIConfMap) > 0 { + config.QemuPCIDevices[hostPCIID] = hostPCIConfMap + } + } + + return + +} + func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { currentConfig, err := NewConfigQemuFromApi(vmr, client) if err != nil { @@ -620,370 +962,9 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e if vmConfig["lock"] != nil { return nil, fmt.Errorf("vm locked, could not obtain config") } - - // vmConfig Sample: map[ cpu:host - // net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0 - // ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048 - // smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1 - // name:terraform-ubuntu1404-template bootdisk:virtio0 - // virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G - // description:Base image - // cores:2 ostype:l26 - - name := "" - if _, isSet := vmConfig["name"]; isSet { - name = vmConfig["name"].(string) - } - description := "" - if _, isSet := vmConfig["description"]; isSet { - description = vmConfig["description"].(string) - } - tags := "" - if _, isSet := vmConfig["tags"]; isSet { - tags = vmConfig["tags"].(string) - } - args := "" - if _, isSet := vmConfig["args"]; isSet { - args = vmConfig["args"].(string) - } - - bios := "seabios" - if _, isSet := vmConfig["bios"]; isSet { - bios = vmConfig["bios"].(string) - } - onboot := true - if _, isSet := vmConfig["onboot"]; isSet { - onboot = Itob(int(vmConfig["onboot"].(float64))) - } - startup := "" - if _, isSet := vmConfig["startup"]; isSet { - startup = vmConfig["startup"].(string) - } - tablet := true - if _, isSet := vmConfig["tablet"]; isSet { - tablet = Itob(int(vmConfig["tablet"].(float64))) - } - - agent := 0 - if _, isSet := vmConfig["agent"]; isSet { - switch vmConfig["agent"].(type) { - case float64: - agent = int(vmConfig["agent"].(float64)) - case string: - AgentConfList := strings.Split(vmConfig["agent"].(string), ",") - agent, _ = strconv.Atoi(AgentConfList[0]) - } - - } - ostype := "other" - if _, isSet := vmConfig["ostype"]; isSet { - ostype = vmConfig["ostype"].(string) - } - memory := 0.0 - if _, isSet := vmConfig["memory"]; isSet { - memory = vmConfig["memory"].(float64) - } - balloon := 0.0 - if _, isSet := vmConfig["balloon"]; isSet { - balloon = vmConfig["balloon"].(float64) - } - cores := 1.0 - if _, isSet := vmConfig["cores"]; isSet { - cores = vmConfig["cores"].(float64) - } - vcpus := 0.0 - if _, isSet := vmConfig["vcpus"]; isSet { - vcpus = vmConfig["vcpus"].(float64) - } - sockets := 1.0 - if _, isSet := vmConfig["sockets"]; isSet { - sockets = vmConfig["sockets"].(float64) - } - cpu := "host" - if _, isSet := vmConfig["cpu"]; isSet { - cpu = vmConfig["cpu"].(string) - } - numa := false - if _, isSet := vmConfig["numa"]; isSet { - numa = Itob(int(vmConfig["numa"].(float64))) - } - //Can be network,disk,cpu,memory,usb - hotplug := "network,disk,usb" - if _, isSet := vmConfig["hotplug"]; isSet { - hotplug = vmConfig["hotplug"].(string) - } - //boot by default from hard disk (c), CD-ROM (d), network (n). - boot := "cdn" - if _, isSet := vmConfig["boot"]; isSet { - boot = vmConfig["boot"].(string) - } - bootdisk := "" - if _, isSet := vmConfig["bootdisk"]; isSet { - bootdisk = vmConfig["bootdisk"].(string) - } - kvm := true - if _, isSet := vmConfig["kvm"]; isSet { - kvm = Itob(int(vmConfig["kvm"].(float64))) - } - scsihw := "lsi" - if _, isSet := vmConfig["scsihw"]; isSet { - scsihw = vmConfig["scsihw"].(string) - } - hookscript := "" - if _, isSet := vmConfig["hookscript"]; isSet { - hookscript = vmConfig["hookscript"].(string) - } - - config = &ConfigQemu{ - Name: name, - Description: strings.TrimSpace(description), - Tags: strings.TrimSpace(tags), - Args: strings.TrimSpace(args), - Bios: bios, - EFIDisk: QemuDevice{}, - Onboot: &onboot, - Startup: startup, - Tablet: &tablet, - Agent: agent, - QemuOs: ostype, - Memory: int(memory), - QemuCores: int(cores), - QemuSockets: int(sockets), - QemuCpu: cpu, - QemuNuma: &numa, - QemuKVM: &kvm, - Hotplug: hotplug, - Boot: boot, - BootDisk: bootdisk, - Scsihw: scsihw, - Hookscript: hookscript, - QemuDisks: QemuDevices{}, - QemuUnusedDisks: QemuDevices{}, - QemuVga: QemuDevice{}, - QemuNetworks: QemuDevices{}, - QemuSerials: QemuDevices{}, - QemuPCIDevices: QemuDevices{}, - QemuUsbs: QemuDevices{}, - Ipconfig: IpconfigMap{}, - } - - if balloon >= 1 { - config.Balloon = int(balloon) - } - if vcpus >= 1 { - config.QemuVcpus = int(vcpus) - } - - // Add Cloud-Init options - if _, isSet := vmConfig["ciuser"]; isSet { - config.CIuser = vmConfig["ciuser"].(string) - } - if _, isSet := vmConfig["cipassword"]; isSet { - config.CIpassword = vmConfig["cipassword"].(string) - } - if _, isSet := vmConfig["cicustom"]; isSet { - config.CIcustom = vmConfig["cicustom"].(string) - } - if _, isSet := vmConfig["searchdomain"]; isSet { - config.Searchdomain = vmConfig["searchdomain"].(string) - } - if _, isSet := vmConfig["nameserver"]; isSet { - config.Nameserver = vmConfig["nameserver"].(string) - } - if _, isSet := vmConfig["sshkeys"]; isSet { - config.Sshkeys, _ = url.PathUnescape(vmConfig["sshkeys"].(string)) - } - - ipconfigNames := []string{} - - for k := range vmConfig { - if ipconfigName := rxIpconfigName.FindStringSubmatch(k); len(ipconfigName) > 0 { - ipconfigNames = append(ipconfigNames, ipconfigName[0]) - } - } - - for _, ipconfigName := range ipconfigNames { - ipConfStr := vmConfig[ipconfigName] - id := rxDeviceID.FindStringSubmatch(ipconfigName) - ipconfigID, _ := strconv.Atoi(id[0]) - config.Ipconfig[ipconfigID] = ipConfStr - } - - config.Disks = QemuStorages{}.mapToStruct(vmConfig) - - if config.Disks != nil && config.Disks.Ide != nil && config.Disks.Ide.Disk_2 != nil && config.Disks.Ide.Disk_2.CdRom != nil { - config.Iso = config.Disks.Ide.Disk_2.CdRom.Iso - } - - // Add unused disks - // unused0:local:100/vm-100-disk-1.qcow2 - unusedDiskNames := []string{} - for k := range vmConfig { - // look for entries from the config in the format "unusedX:" where X is an integer - if unusedDiskName := rxUnusedDiskName.FindStringSubmatch(k); len(unusedDiskName) > 0 { - unusedDiskNames = append(unusedDiskNames, unusedDiskName[0]) - } - } - // if len(unusedDiskNames) > 0 { - // log.Printf("[DEBUG] unusedDiskNames: %v", unusedDiskNames) - // } - - for _, unusedDiskName := range unusedDiskNames { - unusedDiskConfStr := vmConfig[unusedDiskName].(string) - finalDiskConfMap := QemuDevice{} - - // parse "unused0" to get the id '0' as an int - id := rxDeviceID.FindStringSubmatch(unusedDiskName) - diskID, err := strconv.Atoi(id[0]) - if err != nil { - return nil, fmt.Errorf(fmt.Sprintf("Unable to parse unused disk id from input string '%v' tried to convert '%v' to integer.", unusedDiskName, diskID)) - } - finalDiskConfMap["slot"] = diskID - - // parse the attributes from the unused disk - // extract the storage and file path from the unused disk entry - parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") - storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") - finalDiskConfMap["storage"] = storageName - finalDiskConfMap["file"] = fileName - - config.QemuUnusedDisks[diskID] = finalDiskConfMap - } - - //Display - if vga, isSet := vmConfig["vga"]; isSet { - vgaList := strings.Split(vga.(string), ",") - vgaMap := QemuDevice{} - - vgaMap.readDeviceConfig(vgaList) - if len(vgaMap) > 0 { - config.QemuVga = vgaMap - } - } - - // Add networks. - nicNames := []string{} - - for k := range vmConfig { - if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 { - nicNames = append(nicNames, nicName[0]) - } - } - - for _, nicName := range nicNames { - nicConfStr := vmConfig[nicName] - nicConfList := strings.Split(nicConfStr.(string), ",") - - id := rxDeviceID.FindStringSubmatch(nicName) - nicID, _ := strconv.Atoi(id[0]) - model, macaddr := ParseSubConf(nicConfList[0], "=") - - // Add model and MAC address. - nicConfMap := QemuDevice{ - "id": nicID, - "model": model, - "macaddr": macaddr, - } - - // Add rest of device config. - nicConfMap.readDeviceConfig(nicConfList[1:]) - switch nicConfMap["firewall"] { - case 1: - nicConfMap["firewall"] = true - case 0: - nicConfMap["firewall"] = false - } - switch nicConfMap["link_down"] { - case 1: - nicConfMap["link_down"] = true - case 0: - nicConfMap["link_down"] = false - } - - // And device config to networks. - if len(nicConfMap) > 0 { - config.QemuNetworks[nicID] = nicConfMap - } - } - - // Add serials - serialNames := []string{} - - for k := range vmConfig { - if serialName := rxSerialName.FindStringSubmatch(k); len(serialName) > 0 { - serialNames = append(serialNames, serialName[0]) - } - } - - for _, serialName := range serialNames { - id := rxDeviceID.FindStringSubmatch(serialName) - serialID, _ := strconv.Atoi(id[0]) - - serialConfMap := QemuDevice{ - "id": serialID, - "type": vmConfig[serialName], - } - - // And device config to serials map. - if len(serialConfMap) > 0 { - config.QemuSerials[serialID] = serialConfMap - } - } - - // Add usbs - usbNames := []string{} - - for k := range vmConfig { - if usbName := rxUsbName.FindStringSubmatch(k); len(usbName) > 0 { - usbNames = append(usbNames, usbName[0]) - } - } - - for _, usbName := range usbNames { - usbConfStr := vmConfig[usbName] - usbConfList := strings.Split(usbConfStr.(string), ",") - id := rxDeviceID.FindStringSubmatch(usbName) - usbID, _ := strconv.Atoi(id[0]) - _, host := ParseSubConf(usbConfList[0], "=") - - usbConfMap := QemuDevice{ - "id": usbID, - "host": host, - } - - usbConfMap.readDeviceConfig(usbConfList[1:]) - if usbConfMap["usb3"] == 1 { - usbConfMap["usb3"] = true - } - - // And device config to usbs map. - if len(usbConfMap) > 0 { - config.QemuUsbs[usbID] = usbConfMap - } - } - - // hostpci - hostPCInames := []string{} - - for k := range vmConfig { - if hostPCIname := rxPCIName.FindStringSubmatch(k); len(hostPCIname) > 0 { - hostPCInames = append(hostPCInames, hostPCIname[0]) - } - } - - for _, hostPCIname := range hostPCInames { - hostPCIConfStr := vmConfig[hostPCIname] - hostPCIConfList := strings.Split(hostPCIConfStr.(string), ",") - id := rxPCIName.FindStringSubmatch(hostPCIname) - hostPCIID, _ := strconv.Atoi(id[0]) - hostPCIConfMap := QemuDevice{ - "id": hostPCIID, - } - hostPCIConfMap.readDeviceConfig(hostPCIConfList) - // And device config to usbs map. - if len(hostPCIConfMap) > 0 { - config.QemuPCIDevices[hostPCIID] = hostPCIConfMap - } + config, err = ConfigQemu{}.mapToStruct(vmConfig) + if err != nil { + return } // HAstate is return by the api for a vm resource type but not the HAgroup From 6395895354a80355f5622fa7643106c565802f34 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 12 Mar 2023 21:51:43 +0000 Subject: [PATCH 050/191] refactor: put in alphabetical order --- proxmox/config_qemu_disk.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 6ac8ddd5..f393abd7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -541,23 +541,6 @@ type QemuStorages struct { VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` } -func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID uint, params map[string]interface{}) *qemuUpdateChanges { - changes := &qemuUpdateChanges{} - if storages.Ide != nil { - storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, changes) - } - if storages.Sata != nil { - storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, changes) - } - if storages.Scsi != nil { - storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, changes) - } - if storages.VirtIO != nil { - storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, changes) - } - return changes -} - func (storages QemuStorages) mapToApiValues(vmID uint, params map[string]interface{}) { if storages.Ide != nil { storages.Ide.mapToApiValues(nil, vmID, params, nil) @@ -586,6 +569,23 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { return nil } +func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID uint, params map[string]interface{}) *qemuUpdateChanges { + changes := &qemuUpdateChanges{} + if storages.Ide != nil { + storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, changes) + } + if storages.Sata != nil { + storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, changes) + } + if storages.Scsi != nil { + storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, changes) + } + if storages.VirtIO != nil { + storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, changes) + } + return changes +} + type qemuUpdateChanges struct { Delete string Move []qemuDiskShort From 645cac6e737c41f4d4cad365cfadb617a2976a84 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:37:28 +0000 Subject: [PATCH 051/191] refactor: extract to func --- proxmox/config_qemu_disk_ide.go | 62 ++++++++++++++------------ proxmox/config_qemu_disk_sata.go | 62 ++++++++++++++------------ proxmox/config_qemu_disk_scsi.go | 70 +++++++++++++++++------------- proxmox/config_qemu_disk_virtio.go | 64 +++++++++++++++------------ 4 files changed, 145 insertions(+), 113 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 06292bab..9b485388 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -15,6 +15,24 @@ type QemuIdeDisk struct { Storage string `json:"storage,omitempty"` } +func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: ide, + } +} + type QemuIdeDisks struct { Disk_0 *QemuIdeStorage `json:"0,omitempty"` Disk_1 *QemuIdeStorage `json:"1,omitempty"` @@ -73,6 +91,21 @@ type QemuIdePassthrough struct { Size uint //size is only returned and setting it has no effect } +func (passthrough *QemuIdePassthrough) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: ide, + } +} + type QemuIdeStorage struct { CdRom *QemuCdRom `json:"cdrom,omitempty"` CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` @@ -91,35 +124,10 @@ func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { CloudInit: storage.CloudInit, } if storage.Disk != nil { - generalizedStorage.Disk = &qemuDisk{ - AsyncIO: storage.Disk.AsyncIO, - Backup: storage.Disk.Backup, - Bandwidth: storage.Disk.Bandwidth, - Cache: storage.Disk.Cache, - Discard: storage.Disk.Discard, - EmulateSSD: storage.Disk.EmulateSSD, - Format: storage.Disk.Format, - Id: storage.Disk.Id, - Replicate: storage.Disk.Replicate, - Serial: storage.Disk.Serial, - Size: storage.Disk.Size, - Storage: storage.Disk.Storage, - Type: ide, - } + generalizedStorage.Disk = storage.Disk.convertDataStructure() } if storage.Passthrough != nil { - generalizedStorage.Passthrough = &qemuDisk{ - AsyncIO: storage.Passthrough.AsyncIO, - Backup: storage.Passthrough.Backup, - Bandwidth: storage.Passthrough.Bandwidth, - Cache: storage.Passthrough.Cache, - Discard: storage.Passthrough.Discard, - EmulateSSD: storage.Passthrough.EmulateSSD, - File: storage.Passthrough.File, - Replicate: storage.Passthrough.Replicate, - Serial: storage.Passthrough.Serial, - Type: ide, - } + generalizedStorage.Passthrough = storage.Passthrough.convertDataStructure() } return &generalizedStorage } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index dfd50c70..1079e424 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -15,6 +15,24 @@ type QemuSataDisk struct { Storage string `json:"storage,omitempty"` } +func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: sata, + } +} + type QemuSataDisks struct { Disk_0 *QemuSataStorage `json:"0,omitempty"` Disk_1 *QemuSataStorage `json:"1,omitempty"` @@ -85,6 +103,21 @@ type QemuSataPassthrough struct { Size uint //size is only returned and setting it has no effect } +func (passthrough *QemuSataPassthrough) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: sata, + } +} + type QemuSataStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -103,35 +136,10 @@ func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { CloudInit: storage.CloudInit, } if storage.Disk != nil { - generalizedStorage.Disk = &qemuDisk{ - AsyncIO: storage.Disk.AsyncIO, - Backup: storage.Disk.Backup, - Bandwidth: storage.Disk.Bandwidth, - Cache: storage.Disk.Cache, - Discard: storage.Disk.Discard, - EmulateSSD: storage.Disk.EmulateSSD, - Format: storage.Disk.Format, - Id: storage.Disk.Id, - Replicate: storage.Disk.Replicate, - Serial: storage.Disk.Serial, - Size: storage.Disk.Size, - Storage: storage.Disk.Storage, - Type: sata, - } + generalizedStorage.Disk = storage.Disk.convertDataStructure() } if storage.Passthrough != nil { - generalizedStorage.Passthrough = &qemuDisk{ - AsyncIO: storage.Passthrough.AsyncIO, - Backup: storage.Passthrough.Backup, - Bandwidth: storage.Passthrough.Bandwidth, - Cache: storage.Passthrough.Cache, - Discard: storage.Passthrough.Discard, - EmulateSSD: storage.Passthrough.EmulateSSD, - File: storage.Passthrough.File, - Replicate: storage.Passthrough.Replicate, - Serial: storage.Passthrough.Serial, - Type: sata, - } + generalizedStorage.Passthrough = storage.Passthrough.convertDataStructure() } return &generalizedStorage } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 2c1c0a8d..dd1cd340 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -17,6 +17,26 @@ type QemuScsiDisk struct { Storage string `json:"storage,omitempty"` } +func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: scsi, + } +} + type QemuScsiDisks struct { Disk_0 *QemuScsiStorage `json:"0,omitempty"` Disk_1 *QemuScsiStorage `json:"1,omitempty"` @@ -239,6 +259,23 @@ type QemuScsiPassthrough struct { Size uint //size is only returned and setting it has no effect } +func (passthrough *QemuScsiPassthrough) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: scsi, + } +} + type QemuScsiStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -257,39 +294,10 @@ func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { CloudInit: storage.CloudInit, } if storage.Disk != nil { - generalizedStorage.Disk = &qemuDisk{ - AsyncIO: storage.Disk.AsyncIO, - Backup: storage.Disk.Backup, - Bandwidth: storage.Disk.Bandwidth, - Cache: storage.Disk.Cache, - Discard: storage.Disk.Discard, - EmulateSSD: storage.Disk.EmulateSSD, - Format: storage.Disk.Format, - Id: storage.Disk.Id, - IOThread: storage.Disk.IOThread, - ReadOnly: storage.Disk.ReadOnly, - Replicate: storage.Disk.Replicate, - Serial: storage.Disk.Serial, - Size: storage.Disk.Size, - Storage: storage.Disk.Storage, - Type: scsi, - } + generalizedStorage.Disk = storage.Disk.convertDataStructure() } if storage.Passthrough != nil { - generalizedStorage.Passthrough = &qemuDisk{ - AsyncIO: storage.Passthrough.AsyncIO, - Backup: storage.Passthrough.Backup, - Bandwidth: storage.Passthrough.Bandwidth, - Cache: storage.Passthrough.Cache, - Discard: storage.Passthrough.Discard, - EmulateSSD: storage.Passthrough.EmulateSSD, - File: storage.Passthrough.File, - IOThread: storage.Passthrough.IOThread, - ReadOnly: storage.Passthrough.ReadOnly, - Replicate: storage.Passthrough.Replicate, - Serial: storage.Passthrough.Serial, - Type: scsi, - } + generalizedStorage.Passthrough = storage.Passthrough.convertDataStructure() } return &generalizedStorage } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 9f08493e..8101307c 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -16,6 +16,25 @@ type QemuVirtIODisk struct { Storage string `json:"storage,omitempty"` } +func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: virtIO, + } +} + type QemuVirtIODisks struct { Disk_0 *QemuVirtIOStorage `json:"0,omitempty"` Disk_1 *QemuVirtIOStorage `json:"1,omitempty"` @@ -146,6 +165,21 @@ type QemuVirtIOPassthrough struct { Size uint //size is only returned and setting it has no effect } +func (passthrough *QemuVirtIOPassthrough) convertDataStructure() *qemuDisk { + return &qemuDisk{ + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Serial: passthrough.Serial, + Type: virtIO, + } +} + type QemuVirtIOStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -164,36 +198,10 @@ func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { CloudInit: storage.CloudInit, } if storage.Disk != nil { - generalizedStorage.Disk = &qemuDisk{ - AsyncIO: storage.Disk.AsyncIO, - Backup: storage.Disk.Backup, - Bandwidth: storage.Disk.Bandwidth, - Cache: storage.Disk.Cache, - Discard: storage.Disk.Discard, - Format: storage.Disk.Format, - Id: storage.Disk.Id, - IOThread: storage.Disk.IOThread, - ReadOnly: storage.Disk.ReadOnly, - Replicate: storage.Disk.Replicate, - Serial: storage.Disk.Serial, - Size: storage.Disk.Size, - Storage: storage.Disk.Storage, - Type: virtIO, - } + generalizedStorage.Disk = storage.Disk.convertDataStructure() } if storage.Passthrough != nil { - generalizedStorage.Passthrough = &qemuDisk{ - AsyncIO: storage.Passthrough.AsyncIO, - Backup: storage.Passthrough.Backup, - Bandwidth: storage.Passthrough.Bandwidth, - Cache: storage.Passthrough.Cache, - Discard: storage.Passthrough.Discard, - File: storage.Passthrough.File, - IOThread: storage.Passthrough.IOThread, - ReadOnly: storage.Passthrough.ReadOnly, - Serial: storage.Passthrough.Serial, - Type: virtIO, - } + generalizedStorage.Passthrough = storage.Passthrough.convertDataStructure() } return &generalizedStorage } From 02dd49a1bf5ca0483c349e3ec3961de2f9f4f7e3 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:46:25 +0000 Subject: [PATCH 052/191] feat: change to pointer changed to pointer to handle the unspecified case --- proxmox/config_qemu_disk.go | 64 +++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f393abd7..cf089e5f 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -176,34 +176,34 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { // format // media - if disk.Bandwidth.Iops.ReadLimit.Concurrent >= 10 { - settings = settings + ",iops_rd=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Concurrent)) + if disk.Bandwidth.Iops.ReadLimit.Concurrent != nil { + settings = settings + ",iops_rd=" + strconv.Itoa(int(*disk.Bandwidth.Iops.ReadLimit.Concurrent)) } - if disk.Bandwidth.Iops.ReadLimit.Burst >= 10 { - settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Burst)) + if disk.Bandwidth.Iops.ReadLimit.Burst != nil { + settings = settings + ",iops_rd_max=" + strconv.Itoa(int(*disk.Bandwidth.Iops.ReadLimit.Burst)) } - if disk.Bandwidth.Iops.WriteLimit.Concurrent >= 10 { - settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Concurrent)) + if disk.Bandwidth.Iops.WriteLimit.Concurrent != nil { + settings = settings + ",iops_wr=" + strconv.Itoa(int(*disk.Bandwidth.Iops.WriteLimit.Concurrent)) } - if disk.Bandwidth.Iops.WriteLimit.Burst >= 10 { - settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Burst)) + if disk.Bandwidth.Iops.WriteLimit.Burst != nil { + settings = settings + ",iops_wr_max=" + strconv.Itoa(int(*disk.Bandwidth.Iops.WriteLimit.Burst)) } if (disk.Type == scsi || disk.Type == virtIO) && disk.IOThread { settings = settings + ",iothread=1" } - if disk.Bandwidth.Data.ReadLimit.Concurrent >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.Data.ReadLimit.Concurrent) + if disk.Bandwidth.Data.ReadLimit.Concurrent != nil { + settings = settings + fmt.Sprintf(",mbps_rd=%.2f", *disk.Bandwidth.Data.ReadLimit.Concurrent) } - if disk.Bandwidth.Data.ReadLimit.Burst >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.Data.ReadLimit.Burst) + if disk.Bandwidth.Data.ReadLimit.Burst != nil { + settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", *disk.Bandwidth.Data.ReadLimit.Burst) } - if disk.Bandwidth.Data.WriteLimit.Concurrent >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.Data.WriteLimit.Concurrent) + if disk.Bandwidth.Data.WriteLimit.Concurrent != nil { + settings = settings + fmt.Sprintf(",mbps_wr=%.2f", *disk.Bandwidth.Data.WriteLimit.Concurrent) } - if disk.Bandwidth.Data.WriteLimit.Burst >= float32(1) { - settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.Data.WriteLimit.Burst) + if disk.Bandwidth.Data.WriteLimit.Burst != nil { + settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", *disk.Bandwidth.Data.WriteLimit.Burst) } if !disk.Replicate { @@ -270,19 +270,23 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "iops_rd" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Concurrent = uint(tmp) + pointer := uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Concurrent = &pointer } if e[0] == "iops_rd_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Burst = uint(tmp) + pointer := uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Burst = &pointer } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Concurrent = uint(tmp) + pointer := uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Concurrent = &pointer } if e[0] == "iops_wr_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Burst = uint(tmp) + pointer := uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Burst = &pointer } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) @@ -290,19 +294,23 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "mbps_rd" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Concurrent = float32(math.Round(tmp*100) / 100) + pointer := float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Concurrent = &pointer } if e[0] == "mbps_rd_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Burst = float32(math.Round(tmp*100) / 100) + pointer := float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Burst = &pointer } if e[0] == "mbps_wr" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Concurrent = float32(math.Round(tmp*100) / 100) + pointer := float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Concurrent = &pointer } if e[0] == "mbps_wr_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Burst = float32(math.Round(tmp*100) / 100) + pointer := float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Burst = &pointer } if e[0] == "replicate" { disk.Replicate, _ = strconv.ParseBool(e[1]) @@ -355,8 +363,8 @@ type QemuDiskBandwidthData struct { } type QemuDiskBandwidthDataLimit struct { - Concurrent float32 - Burst float32 + Burst *float32 // nil = default + Concurrent *float32 // nil = unlimited } type QemuDiskBandwidthIops struct { @@ -365,8 +373,8 @@ type QemuDiskBandwidthIops struct { } type QemuDiskBandwidthIopsLimit struct { - Concurrent uint - Burst uint + Burst *uint // nil = default + Concurrent *uint // nil = unlimited } type QemuDiskCache string From 297dc143d06b17849935285f8fab7c73a40db915 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:49:56 +0000 Subject: [PATCH 053/191] fix: typo --- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_virtio.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 9b485388..36ed4a60 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -3,7 +3,7 @@ package proxmox type QemuIdeDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` - Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 1079e424..b299e413 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -3,7 +3,7 @@ package proxmox type QemuSataDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` - Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index dd1cd340..6694d3dd 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -3,7 +3,7 @@ package proxmox type QemuScsiDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` - Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 8101307c..13310837 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -3,7 +3,7 @@ package proxmox type QemuVirtIODisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` - Bandwidth QemuDiskBandwidth `json:"bandwith,omitempty"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` Format *QemuDiskFormat `json:"format,omitempty"` From 34ea69232c6b6e5ea8043f983574125335cdeb19 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:07:15 +0000 Subject: [PATCH 054/191] feat: add Validator for `QemuDiskBandwidth` and sub types --- proxmox/config_qemu_disk.go | 44 ++++++++ proxmox/config_qemu_disk_test.go | 178 +++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index cf089e5f..6c018fa2 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -357,26 +357,70 @@ type QemuDiskBandwidth struct { Iops QemuDiskBandwidthIops } +func (bandwidth QemuDiskBandwidth) Validate() error { + err := bandwidth.Data.Validate() + if err != nil { + return err + } + return bandwidth.Iops.Validate() +} + type QemuDiskBandwidthData struct { ReadLimit QemuDiskBandwidthDataLimit WriteLimit QemuDiskBandwidthDataLimit } +func (data QemuDiskBandwidthData) Validate() error { + err := data.ReadLimit.Validate() + if err != nil { + return err + } + return data.WriteLimit.Validate() +} + type QemuDiskBandwidthDataLimit struct { Burst *float32 // nil = default Concurrent *float32 // nil = unlimited } +func (limit QemuDiskBandwidthDataLimit) Validate() error { + if limit.Burst != nil && *limit.Burst < 1 { + return errors.New("burst may not be lower then 1") + } + if limit.Concurrent != nil && *limit.Concurrent < 1 { + return errors.New("concurrent may not be lower then 1") + } + return nil +} + type QemuDiskBandwidthIops struct { ReadLimit QemuDiskBandwidthIopsLimit WriteLimit QemuDiskBandwidthIopsLimit } +func (iops QemuDiskBandwidthIops) Validate() error { + err := iops.ReadLimit.Validate() + if err != nil { + return err + } + return iops.WriteLimit.Validate() +} + type QemuDiskBandwidthIopsLimit struct { Burst *uint // nil = default Concurrent *uint // nil = unlimited } +func (limit QemuDiskBandwidthIopsLimit) Validate() error { + if limit.Burst != nil && *limit.Burst < 10 { + return errors.New("burst may not be lower then 10") + } + if limit.Concurrent != nil && *limit.Concurrent < 10 { + return errors.New("concurrent may not be lower then 1") + } + return nil +} + type QemuDiskCache string const ( diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 25274d88..e83ff256 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -30,6 +30,184 @@ func Test_QemuDiskAsyncIO_Validate(t *testing.T) { } } +func Test_QemuDiskBandwidth_Validate(t *testing.T) { + float0 := float32(0) + float0a := float32(0.99) + float1 := float32(1) + uint0 := uint(0) + uint9 := uint(9) + uint10 := uint(10) + testData := []struct { + input QemuDiskBandwidth + err bool + }{ + // Valid + {input: QemuDiskBandwidth{}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}}, + // Invalid + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + +func Test_QemuDiskBandwidthData_Validate(t *testing.T) { + float0 := float32(0) + float0a := float32(0.99) + float1 := float32(1) + testData := []struct { + input QemuDiskBandwidthData + err bool + }{ + // Valid + {input: QemuDiskBandwidthData{}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}, + // Invalid + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + +func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { + float0 := float32(0) + float0a := float32(0.99) + float1 := float32(1) + testData := []struct { + input QemuDiskBandwidthDataLimit + err bool + }{ + // Valid + {input: QemuDiskBandwidthDataLimit{}}, + {input: QemuDiskBandwidthDataLimit{Burst: &float1}}, + {input: QemuDiskBandwidthDataLimit{Concurrent: &float1}}, + // Invalid + {input: QemuDiskBandwidthDataLimit{Burst: &float0}, err: true}, + {input: QemuDiskBandwidthDataLimit{Burst: &float0a}, err: true}, + {input: QemuDiskBandwidthDataLimit{Concurrent: &float0}, err: true}, + {input: QemuDiskBandwidthDataLimit{Concurrent: &float0a}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + +func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { + uint0 := uint(0) + uint9 := uint(9) + uint10 := uint(10) + testData := []struct { + input QemuDiskBandwidthIops + err bool + }{ + // Valid + {input: QemuDiskBandwidthIops{}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}, + // Invalid + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + +func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { + uint0 := uint(0) + uint9 := uint(9) + uint10 := uint(10) + testData := []struct { + input QemuDiskBandwidthIopsLimit + err bool + }{ + // Valid + {input: QemuDiskBandwidthIopsLimit{}}, + {input: QemuDiskBandwidthIopsLimit{Burst: &uint10}}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}, + // Invalid + {input: QemuDiskBandwidthIopsLimit{Burst: &uint0}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Burst: &uint9}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskCache_Validate(t *testing.T) { testData := []struct { input QemuDiskCache From 5412645083ab6bf5cd82d26ea6612faf5ef6e442 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:14:46 +0000 Subject: [PATCH 055/191] feat: add Validate func for `IsoFile` --- proxmox/config_qemu_disk.go | 12 +++++++++++- proxmox/config_qemu_disk_test.go | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 6c018fa2..af47d24b 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -10,12 +10,22 @@ import ( ) type IsoFile struct { - Storage string `json:"storage"` File string `json:"file"` + Storage string `json:"storage"` // Size can only be retrieved, setting it has no effect Size string `json:"size"` } +func (iso IsoFile) Validate() error { + if iso.File == "" { + return errors.New("file may not be empty") + } + if iso.Storage == "" { + return errors.New("storage may not be empty") + } + return nil +} + type QemuCdRom struct { Iso *IsoFile `json:"iso,omitempty"` // Passthrough and File are mutually exclusive diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index e83ff256..6aab269b 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -7,6 +7,28 @@ import ( "github.com/stretchr/testify/require" ) +func Test_IsoFile_Validate(t *testing.T) { + testData := []struct { + input IsoFile + err bool + }{ + // Valid + {input: IsoFile{File: "anything", Storage: "something"}}, + // Invalid + {input: IsoFile{}, err: true}, + {input: IsoFile{File: "anything"}, err: true}, + {input: IsoFile{Storage: "something"}, err: true}, + {input: IsoFile{Size: "something"}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { input QemuDiskAsyncIO From 40731aa396d2af6feab9ef5c746b9bace44c1a19 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:23:27 +0000 Subject: [PATCH 056/191] feat: add Validate func for `QemuCdRom` --- proxmox/config_qemu_disk.go | 13 +++++++++++++ proxmox/config_qemu_disk_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index af47d24b..c9b9d7be 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -56,6 +56,19 @@ func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { return &QemuCdRom{Passthrough: false} } +func (cdRom QemuCdRom) Validate() error { + if cdRom.Iso != nil { + err := cdRom.Iso.Validate() + if err != nil { + return err + } + if cdRom.Passthrough { + return errors.New("iso and passthrough are mutually exclusive") + } + } + return nil +} + type qemuCdRom struct { // "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M" Passthrough bool diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 6aab269b..f42a094b 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -29,6 +29,31 @@ func Test_IsoFile_Validate(t *testing.T) { } } +func Test_QemuCdRom_Validate(t *testing.T) { + testData := []struct { + input QemuCdRom + err bool + }{ + // Valid + {input: QemuCdRom{}}, + {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "Something"}}}, + {input: QemuCdRom{Passthrough: true}}, + // Invalid + {input: QemuCdRom{Iso: &IsoFile{}}, err: true}, + {input: QemuCdRom{Iso: &IsoFile{File: "anything"}}, err: true}, + {input: QemuCdRom{Iso: &IsoFile{Storage: "something"}}, err: true}, + {input: QemuCdRom{Iso: &IsoFile{Size: "something"}}, err: true}, + {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "something"}, Passthrough: true}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { input QemuDiskAsyncIO From 65ea0b2c1155db04de9e55b5860ef09a94a0c019 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:45:01 +0000 Subject: [PATCH 057/191] feat: make format optional --- proxmox/config_qemu_disk.go | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index c9b9d7be..308b6b65 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -70,13 +70,13 @@ func (cdRom QemuCdRom) Validate() error { } type qemuCdRom struct { + CdRom bool // "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M" Passthrough bool Storage string - // FileType is only set for Cloud init drives, this value will be used to check if it is a normal cdrom or cloud init drive. - FileType string - File string - Size string + Format *QemuDiskFormat // Only set for Cloud-init drives + File string + Size string } func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { @@ -104,11 +104,12 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { if len(tmpFile) == 2 { tmpFileType := strings.Split(tmpFile[1], ".") if len(tmpFileType) > 1 { - fileType := tmpFileType[len(tmpFileType)-1] + fileType := QemuDiskFormat(tmpFileType[len(tmpFileType)-1]) if fileType == "iso" { for _, e := range settings { if e[0] == "size" { return &qemuCdRom{ + CdRom: true, Storage: tmpStorage[0], File: tmpFile[1], Size: e[1], @@ -117,9 +118,9 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { } } else { return &qemuCdRom{ - Storage: tmpStorage[0], - File: tmpFile[1], - FileType: fileType, + Storage: tmpStorage[0], + File: tmpFile[1], + Format: &fileType, } } } @@ -129,19 +130,25 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { } type QemuCloudInitDisk struct { - FileType string - Storage string + Format *QemuDiskFormat `json:"format,omitempty"` + Storage string `json:"storage,omitempty"` } // TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { - return cloudInit.Storage + ":cloudinit,format=" + cloudInit.FileType + var fileType string + if cloudInit.Format == nil { + fileType = "raw" + } else { + fileType = string(*cloudInit.Format) + } + return cloudInit.Storage + ":cloudinit,format=" + fileType } func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { return &QemuCloudInitDisk{ - Storage: settings.Storage, - FileType: settings.FileType, + Storage: settings.Storage, + Format: settings.Format, } } From 3d39fd5381fcf415bef28c524226673ae645d9b1 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:49:20 +0000 Subject: [PATCH 058/191] feat: allow for empty case --- proxmox/config_qemu_disk.go | 2 +- proxmox/config_qemu_disk_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 308b6b65..38c5a840 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -483,7 +483,7 @@ const ( func (format QemuDiskFormat) Validate() error { switch format { - case QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: + case "", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: return nil } return fmt.Errorf("format can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index f42a094b..8604e492 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -286,6 +286,7 @@ func Test_QemuDiskFormat_Validate(t *testing.T) { err bool }{ // Valid + {input: ""}, {input: QemuDiskFormat_Cow}, {input: QemuDiskFormat_Cloop}, {input: QemuDiskFormat_Qcow}, From f5c740e73d14d3c23034754b43c7173463cb26cb Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:59:38 +0000 Subject: [PATCH 059/191] fix: format should never be empty --- proxmox/config_qemu_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 38c5a840..308b6b65 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -483,7 +483,7 @@ const ( func (format QemuDiskFormat) Validate() error { switch format { - case "", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: + case QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: return nil } return fmt.Errorf("format can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) From 9ef20edd26bf8e244600f2fff66e48f900cea6c1 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:03:05 +0000 Subject: [PATCH 060/191] feat: add Validate func for `QemuCloudInitDisk` --- proxmox/config_qemu_disk.go | 12 ++++++++++++ proxmox/config_qemu_disk_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 308b6b65..ab78a883 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -152,6 +152,18 @@ func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { } } +func (cloudInit QemuCloudInitDisk) Validate() error { + if cloudInit.Format != nil { + if err := cloudInit.Format.Validate(); err != nil { + return err + } + } + if cloudInit.Storage == "" { + return errors.New("storage should not be empty") + } + return nil +} + type qemuDisk struct { AsyncIO QemuDiskAsyncIO Backup bool diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 8604e492..87af395a 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -54,6 +54,32 @@ func Test_QemuCdRom_Validate(t *testing.T) { } } +func Test_QemuCloudInitDisk_Validate(t *testing.T) { + formatRaw := QemuDiskFormat_Raw + formatEmpty := QemuDiskFormat("") + formatInvalid := QemuDiskFormat("invalid") + testData := []struct { + input QemuCloudInitDisk + err bool + }{ + // Valid + {input: QemuCloudInitDisk{Storage: "anything"}}, + {input: QemuCloudInitDisk{Storage: "anything", Format: &formatRaw}}, + // Invalid + {input: QemuCloudInitDisk{}, err: true}, + {input: QemuCloudInitDisk{Format: &formatRaw}, err: true}, + {input: QemuCloudInitDisk{Storage: "anything", Format: &formatEmpty}, err: true}, + {input: QemuCloudInitDisk{Storage: "anything", Format: &formatInvalid}, err: true}, + } + for _, e := range testData { + if e.err { + require.Error(t, e.input.Validate()) + } else { + require.NoError(t, e.input.Validate()) + } + } +} + func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { input QemuDiskAsyncIO From e9d6cc101bcf91243246a73ca9c747ee5d84a5d2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:04:58 +0000 Subject: [PATCH 061/191] fix: remove empty case --- proxmox/config_qemu_disk_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 87af395a..a981ef83 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -312,7 +312,6 @@ func Test_QemuDiskFormat_Validate(t *testing.T) { err bool }{ // Valid - {input: ""}, {input: QemuDiskFormat_Cow}, {input: QemuDiskFormat_Cloop}, {input: QemuDiskFormat_Qcow}, From 01808d2aef6c32b94e0bafabc6e4b7ad9079679c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:06:39 +0000 Subject: [PATCH 062/191] fix: allow for empty case --- proxmox/config_qemu_disk.go | 2 +- proxmox/config_qemu_disk_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index ab78a883..797bc296 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -388,7 +388,7 @@ const ( func (asyncIO QemuDiskAsyncIO) Validate() error { switch asyncIO { - case QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring: + case "", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring: return nil } return fmt.Errorf("asyncio can only be one of the following values: %s,%s,%s", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring) diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index a981ef83..444041a5 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -86,6 +86,7 @@ func Test_QemuDiskAsyncIO_Validate(t *testing.T) { err bool }{ // Valid + {input: ""}, {input: QemuDiskAsyncIO_Native}, {input: QemuDiskAsyncIO_Threads}, {input: QemuDiskAsyncIO_IOuring}, From ddfe86605018f6ff5900e5f48bc1ac4daf68a23f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:14:24 +0000 Subject: [PATCH 063/191] refactor: make code more reusable --- proxmox/config_qemu_disk_ide.go | 20 ++++++-- proxmox/config_qemu_disk_sata.go | 24 +++++++--- proxmox/config_qemu_disk_scsi.go | 74 +++++++++++++++++------------- proxmox/config_qemu_disk_virtio.go | 44 +++++++++++------- 4 files changed, 105 insertions(+), 57 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 36ed4a60..444bb035 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -1,5 +1,7 @@ package proxmox +import "strconv" + type QemuIdeDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` @@ -46,10 +48,20 @@ func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "ide0", params, changes) - disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "ide1", params, changes) - disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "ide2", params, changes) - disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "ide3", params, changes) + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "ide"+strconv.Itoa(int(i)), params, changes) + } +} + +func (disks QemuIdeDisks) mapToIntMap() map[uint8]*QemuIdeStorage { + return map[uint8]*QemuIdeStorage{ + 0: disks.Disk_0, + 1: disks.Disk_1, + 2: disks.Disk_2, + 3: disks.Disk_3, + } } // TODO write test diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index b299e413..44d472f9 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -1,5 +1,7 @@ package proxmox +import "strconv" + type QemuSataDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` @@ -48,12 +50,22 @@ func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "sata0", params, changes) - disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "sata1", params, changes) - disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "sata2", params, changes) - disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "sata3", params, changes) - disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "sata4", params, changes) - disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "sata5", params, changes) + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "sata"+strconv.Itoa(int(i)), params, changes) + } +} + +func (disks QemuSataDisks) mapToIntMap() map[uint8]*QemuSataStorage { + return map[uint8]*QemuSataStorage{ + 0: disks.Disk_0, + 1: disks.Disk_1, + 2: disks.Disk_2, + 3: disks.Disk_3, + 4: disks.Disk_4, + 5: disks.Disk_5, + } } // TODO write test diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 6694d3dd..22fc98c0 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -1,5 +1,7 @@ package proxmox +import "strconv" + type QemuScsiDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` @@ -77,37 +79,47 @@ func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "scsi0", params, changes) - disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "scsi1", params, changes) - disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "scsi2", params, changes) - disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "scsi3", params, changes) - disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "scsi4", params, changes) - disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "scsi5", params, changes) - disks.Disk_6.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_6.convertDataStructure(), vmID, "scsi6", params, changes) - disks.Disk_7.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_7.convertDataStructure(), vmID, "scsi7", params, changes) - disks.Disk_8.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_8.convertDataStructure(), vmID, "scsi8", params, changes) - disks.Disk_9.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_9.convertDataStructure(), vmID, "scsi9", params, changes) - disks.Disk_10.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_10.convertDataStructure(), vmID, "scsi10", params, changes) - disks.Disk_11.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_11.convertDataStructure(), vmID, "scsi11", params, changes) - disks.Disk_12.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_12.convertDataStructure(), vmID, "scsi12", params, changes) - disks.Disk_13.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_13.convertDataStructure(), vmID, "scsi13", params, changes) - disks.Disk_14.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_14.convertDataStructure(), vmID, "scsi14", params, changes) - disks.Disk_15.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_15.convertDataStructure(), vmID, "scsi15", params, changes) - disks.Disk_16.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_16.convertDataStructure(), vmID, "scsi16", params, changes) - disks.Disk_17.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_17.convertDataStructure(), vmID, "scsi17", params, changes) - disks.Disk_18.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_18.convertDataStructure(), vmID, "scsi18", params, changes) - disks.Disk_19.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_19.convertDataStructure(), vmID, "scsi19", params, changes) - disks.Disk_20.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_20.convertDataStructure(), vmID, "scsi20", params, changes) - disks.Disk_21.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_21.convertDataStructure(), vmID, "scsi21", params, changes) - disks.Disk_22.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_22.convertDataStructure(), vmID, "scsi22", params, changes) - disks.Disk_23.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_23.convertDataStructure(), vmID, "scsi23", params, changes) - disks.Disk_24.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_24.convertDataStructure(), vmID, "scsi24", params, changes) - disks.Disk_25.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_25.convertDataStructure(), vmID, "scsi25", params, changes) - disks.Disk_26.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_26.convertDataStructure(), vmID, "scsi26", params, changes) - disks.Disk_27.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_27.convertDataStructure(), vmID, "scsi27", params, changes) - disks.Disk_28.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_28.convertDataStructure(), vmID, "scsi28", params, changes) - disks.Disk_29.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_29.convertDataStructure(), vmID, "scsi29", params, changes) - disks.Disk_30.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_30.convertDataStructure(), vmID, "scsi30", params, changes) + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "scsi"+strconv.Itoa(int(i)), params, changes) + } +} + +func (disks QemuScsiDisks) mapToIntMap() map[uint8]*QemuScsiStorage { + return map[uint8]*QemuScsiStorage{ + 0: disks.Disk_0, + 1: disks.Disk_1, + 2: disks.Disk_2, + 3: disks.Disk_3, + 4: disks.Disk_4, + 5: disks.Disk_5, + 6: disks.Disk_6, + 7: disks.Disk_7, + 8: disks.Disk_8, + 9: disks.Disk_9, + 10: disks.Disk_10, + 11: disks.Disk_11, + 12: disks.Disk_12, + 13: disks.Disk_13, + 14: disks.Disk_14, + 15: disks.Disk_15, + 16: disks.Disk_16, + 17: disks.Disk_17, + 18: disks.Disk_18, + 19: disks.Disk_19, + 20: disks.Disk_20, + 21: disks.Disk_21, + 22: disks.Disk_22, + 23: disks.Disk_23, + 24: disks.Disk_24, + 25: disks.Disk_25, + 26: disks.Disk_26, + 27: disks.Disk_27, + 28: disks.Disk_28, + 29: disks.Disk_29, + 30: disks.Disk_30, + } } // TODO write test diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 13310837..69389b7f 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -1,5 +1,7 @@ package proxmox +import "strconv" + type QemuVirtIODisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` Backup bool `json:"backup,omitempty"` @@ -60,22 +62,32 @@ func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID if currentDisks != nil { tmpCurrentDisks = *currentDisks } - disks.Disk_0.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_0.convertDataStructure(), vmID, "virtio0", params, changes) - disks.Disk_1.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_1.convertDataStructure(), vmID, "virtio1", params, changes) - disks.Disk_2.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_2.convertDataStructure(), vmID, "virtio2", params, changes) - disks.Disk_3.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_3.convertDataStructure(), vmID, "virtio3", params, changes) - disks.Disk_4.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_4.convertDataStructure(), vmID, "virtio4", params, changes) - disks.Disk_5.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_5.convertDataStructure(), vmID, "virtio5", params, changes) - disks.Disk_6.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_6.convertDataStructure(), vmID, "virtio6", params, changes) - disks.Disk_7.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_7.convertDataStructure(), vmID, "virtio7", params, changes) - disks.Disk_8.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_8.convertDataStructure(), vmID, "virtio8", params, changes) - disks.Disk_9.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_9.convertDataStructure(), vmID, "virtio9", params, changes) - disks.Disk_10.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_10.convertDataStructure(), vmID, "virtio10", params, changes) - disks.Disk_11.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_11.convertDataStructure(), vmID, "virtio11", params, changes) - disks.Disk_12.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_12.convertDataStructure(), vmID, "virtio12", params, changes) - disks.Disk_13.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_13.convertDataStructure(), vmID, "virtio13", params, changes) - disks.Disk_14.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_14.convertDataStructure(), vmID, "virtio14", params, changes) - disks.Disk_15.convertDataStructure().markDiskChanges(tmpCurrentDisks.Disk_15.convertDataStructure(), vmID, "virtio15", params, changes) + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "virtio"+strconv.Itoa(int(i)), params, changes) + } +} + +func (disks QemuVirtIODisks) mapToIntMap() map[uint8]*QemuVirtIOStorage { + return map[uint8]*QemuVirtIOStorage{ + 0: disks.Disk_0, + 1: disks.Disk_1, + 2: disks.Disk_2, + 3: disks.Disk_3, + 4: disks.Disk_4, + 5: disks.Disk_5, + 6: disks.Disk_6, + 7: disks.Disk_7, + 8: disks.Disk_8, + 9: disks.Disk_9, + 10: disks.Disk_10, + 11: disks.Disk_11, + 12: disks.Disk_12, + 13: disks.Disk_13, + 14: disks.Disk_14, + 15: disks.Disk_15, + } } // TODO write test From 1c1908c6d9ecf123e1c44b79929376be306bcf16 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:16:59 +0000 Subject: [PATCH 064/191] fix: check correct value --- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_virtio.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 444bb035..09db6719 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -149,7 +149,7 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { - if tmpCdRom.FileType == "" { + if tmpCdRom.CdRom { return &QemuIdeStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} } else { return &QemuIdeStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 44d472f9..49778505 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -161,7 +161,7 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { - if tmpCdRom.FileType == "" { + if tmpCdRom.CdRom { return &QemuSataStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} } else { return &QemuSataStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 22fc98c0..13d32c18 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -319,7 +319,7 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { - if tmpCdRom.FileType == "" { + if tmpCdRom.CdRom { return &QemuScsiStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} } else { return &QemuScsiStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 69389b7f..f983be93 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -223,7 +223,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { - if tmpCdRom.FileType == "" { + if tmpCdRom.CdRom { return &QemuVirtIOStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} } else { return &QemuVirtIOStorage{CloudInit: QemuCloudInitDisk{}.mapToStruct(*tmpCdRom)} From cb072a65e65c7f2b6017da2cb520d932c02662f6 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 13:49:56 +0000 Subject: [PATCH 065/191] feat: add `Disk` property to `qemuDisk` --- proxmox/config_qemu_disk.go | 1 + proxmox/config_qemu_disk_ide.go | 1 + proxmox/config_qemu_disk_sata.go | 1 + proxmox/config_qemu_disk_scsi.go | 1 + proxmox/config_qemu_disk_virtio.go | 1 + 5 files changed, 5 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 797bc296..351d78fc 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -170,6 +170,7 @@ type qemuDisk struct { Bandwidth QemuDiskBandwidth Cache QemuDiskCache Discard bool + Disk bool // true = disk, false = passthrough EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type File string // Only set for Passthrough. diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 09db6719..f66cd482 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -24,6 +24,7 @@ func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { Bandwidth: disk.Bandwidth, Cache: disk.Cache, Discard: disk.Discard, + Disk: true, EmulateSSD: disk.EmulateSSD, Format: disk.Format, Id: disk.Id, diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 49778505..19c4f313 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -24,6 +24,7 @@ func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { Bandwidth: disk.Bandwidth, Cache: disk.Cache, Discard: disk.Discard, + Disk: true, EmulateSSD: disk.EmulateSSD, Format: disk.Format, Id: disk.Id, diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 13d32c18..dee205a6 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -26,6 +26,7 @@ func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { Bandwidth: disk.Bandwidth, Cache: disk.Cache, Discard: disk.Discard, + Disk: true, EmulateSSD: disk.EmulateSSD, Format: disk.Format, Id: disk.Id, diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index f983be93..6cba1280 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -25,6 +25,7 @@ func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { Bandwidth: disk.Bandwidth, Cache: disk.Cache, Discard: disk.Discard, + Disk: true, Format: disk.Format, Id: disk.Id, IOThread: disk.IOThread, From 7952dd3bcecbd997a015a57c4d455803417fea7d Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 14:46:22 +0000 Subject: [PATCH 066/191] refactor: make `QemuDiskFormat` required reduce config complexity for now --- proxmox/config_qemu_disk.go | 22 +++++++--------------- proxmox/config_qemu_disk_test.go | 9 ++++----- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 351d78fc..74b8d6d6 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -74,7 +74,7 @@ type qemuCdRom struct { // "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M" Passthrough bool Storage string - Format *QemuDiskFormat // Only set for Cloud-init drives + Format QemuDiskFormat // Only set for Cloud-init drives File string Size string } @@ -120,7 +120,7 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { return &qemuCdRom{ Storage: tmpStorage[0], File: tmpFile[1], - Format: &fileType, + Format: fileType, } } } @@ -130,19 +130,13 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { } type QemuCloudInitDisk struct { - Format *QemuDiskFormat `json:"format,omitempty"` - Storage string `json:"storage,omitempty"` + Format QemuDiskFormat `json:"format,omitempty"` + Storage string `json:"storage,omitempty"` } // TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { - var fileType string - if cloudInit.Format == nil { - fileType = "raw" - } else { - fileType = string(*cloudInit.Format) - } - return cloudInit.Storage + ":cloudinit,format=" + fileType + return cloudInit.Storage + ":cloudinit,format=" + string(cloudInit.Format) } func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { @@ -153,10 +147,8 @@ func (QemuCloudInitDisk) mapToStruct(settings qemuCdRom) *QemuCloudInitDisk { } func (cloudInit QemuCloudInitDisk) Validate() error { - if cloudInit.Format != nil { - if err := cloudInit.Format.Validate(); err != nil { - return err - } + if err := cloudInit.Format.Validate(); err != nil { + return err } if cloudInit.Storage == "" { return errors.New("storage should not be empty") diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 444041a5..b58fecbd 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -63,13 +63,12 @@ func Test_QemuCloudInitDisk_Validate(t *testing.T) { err bool }{ // Valid - {input: QemuCloudInitDisk{Storage: "anything"}}, - {input: QemuCloudInitDisk{Storage: "anything", Format: &formatRaw}}, + {input: QemuCloudInitDisk{Storage: "anything", Format: formatRaw}}, // Invalid {input: QemuCloudInitDisk{}, err: true}, - {input: QemuCloudInitDisk{Format: &formatRaw}, err: true}, - {input: QemuCloudInitDisk{Storage: "anything", Format: &formatEmpty}, err: true}, - {input: QemuCloudInitDisk{Storage: "anything", Format: &formatInvalid}, err: true}, + {input: QemuCloudInitDisk{Format: formatRaw}, err: true}, + {input: QemuCloudInitDisk{Storage: "anything", Format: formatEmpty}, err: true}, + {input: QemuCloudInitDisk{Storage: "anything", Format: formatInvalid}, err: true}, } for _, e := range testData { if e.err { From 1a3d4ed766349254ccda8b16c4997f479a140f3f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 14:57:03 +0000 Subject: [PATCH 067/191] refactor: make `QemuDiskFormat` required reduce config complexity for now --- proxmox/config_qemu_disk.go | 16 ++++++---------- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_virtio.go | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 74b8d6d6..f2a942e7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -165,10 +165,10 @@ type qemuDisk struct { Disk bool // true = disk, false = passthrough EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type - File string // Only set for Passthrough. - Format *QemuDiskFormat // Only set for Disk - Id *uint // Only set for Disk - IOThread bool // Only set for scsi,virtio + File string // Only set for Passthrough. + Format QemuDiskFormat // Only set for Disk + Id *uint // Only set for Disk + IOThread bool // Only set for scsi,virtio Number uint ReadOnly bool // Only set for scsi,virtio Replicate bool @@ -187,7 +187,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { } else { // test:100/vm-100-disk-0.raw tmpId := strconv.Itoa(int(vmID)) - settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(*disk.Id)) + "." + string(*disk.Format) + settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(*disk.Id)) + "." + string(disk.Format) } } @@ -274,8 +274,7 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(diskAndNumberAndFormat) == 2 { idAndFormat := strings.Split(diskAndNumberAndFormat[1], ".") if len(idAndFormat) == 2 { - tmpFormat := QemuDiskFormat(idAndFormat[1]) - disk.Format = &tmpFormat + disk.Format = QemuDiskFormat(idAndFormat[1]) tmp := strings.Split(idAndFormat[0], "-") if len(tmp) > 1 { tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) @@ -583,9 +582,6 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui if storage.Disk.Id == nil { storage.Disk.Id = currentStorage.Disk.Id } - if storage.Disk.Format == nil { - storage.Disk.Format = currentStorage.Disk.Format - } if storage.Disk.Storage != currentStorage.Disk.Storage { changes.Move = append(changes.Move, qemuDiskShort{ Id: id, diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index f66cd482..e8b2ec8d 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -9,7 +9,7 @@ type QemuIdeDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Format *QemuDiskFormat `json:"format,omitempty"` + Format QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 19c4f313..d8f30216 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -9,7 +9,7 @@ type QemuSataDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Format *QemuDiskFormat `json:"format,omitempty"` + Format QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` Replicate bool `json:"replicate,omitempty"` Serial QemuDiskSerial `json:"serial,omitempty"` diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index dee205a6..964a5752 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -9,7 +9,7 @@ type QemuScsiDisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` EmulateSSD bool `json:"emulatessd,omitempty"` - Format *QemuDiskFormat `json:"format,omitempty"` + Format QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 6cba1280..2e041885 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -8,7 +8,7 @@ type QemuVirtIODisk struct { Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard,omitempty"` - Format *QemuDiskFormat `json:"format,omitempty"` + Format QemuDiskFormat `json:"format,omitempty"` Id *uint `json:"id,omitempty"` IOThread bool `json:"iothread,omitempty"` ReadOnly bool `json:"readonly,omitempty"` From 3a188d7b57bb621878e54d2dd1f0ca3d3d9e289d Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 17:39:44 +0000 Subject: [PATCH 068/191] test: match exact error --- proxmox/config_qemu_disk.go | 6 +++++- proxmox/config_qemu_disk_test.go | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f2a942e7..244c4d9a 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -378,12 +378,16 @@ const ( QemuDiskAsyncIO_IOuring QemuDiskAsyncIO = "io_uring" ) +func (QemuDiskAsyncIO) Error() error { + return fmt.Errorf("asyncio can only be one of the following values: %s,%s,%s", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring) +} + func (asyncIO QemuDiskAsyncIO) Validate() error { switch asyncIO { case "", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring: return nil } - return fmt.Errorf("asyncio can only be one of the following values: %s,%s,%s", QemuDiskAsyncIO_Native, QemuDiskAsyncIO_Threads, QemuDiskAsyncIO_IOuring) + return QemuDiskAsyncIO("").Error() } type QemuDiskBandwidth struct { diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index b58fecbd..c345ca6b 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -82,7 +82,7 @@ func Test_QemuCloudInitDisk_Validate(t *testing.T) { func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { input QemuDiskAsyncIO - err bool + err error }{ // Valid {input: ""}, @@ -90,13 +90,13 @@ func Test_QemuDiskAsyncIO_Validate(t *testing.T) { {input: QemuDiskAsyncIO_Threads}, {input: QemuDiskAsyncIO_IOuring}, // Invalid - {input: "bla", err: true}, - {input: "invalid value", err: true}, - {input: "!@#$", err: true}, + {input: "bla", err: QemuDiskAsyncIO("").Error()}, + {input: "invalid value", err: QemuDiskAsyncIO("").Error()}, + {input: "!@#$", err: QemuDiskAsyncIO("").Error()}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From ddf2acfe40129c6ca0aca4f006e0091bd5871614 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 17:50:31 +0000 Subject: [PATCH 069/191] test: match exact error --- proxmox/config_qemu_disk.go | 8 ++++++-- proxmox/config_qemu_disk_test.go | 13 +++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 244c4d9a..b8aec495 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -469,12 +469,16 @@ const ( QemuDiskCache_DirectSync QemuDiskCache = "directsync" ) +func (QemuDiskCache) Error() error { + return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) +} + func (cache QemuDiskCache) Validate() error { switch cache { - case QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync: + case "", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync: return nil } - return fmt.Errorf("cache can only be one of the following values: %s,%s,%s,%s,%s", QemuDiskCache_None, QemuDiskCache_WriteThrough, QemuDiskCache_WriteBack, QemuDiskCache_Unsafe, QemuDiskCache_DirectSync) + return QemuDiskCache("").Error() } type QemuDiskFormat string diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index c345ca6b..7814a7f3 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -284,22 +284,23 @@ func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { func Test_QemuDiskCache_Validate(t *testing.T) { testData := []struct { input QemuDiskCache - err bool + err error }{ // Valid + {input: ""}, {input: QemuDiskCache_None}, {input: QemuDiskCache_WriteThrough}, {input: QemuDiskCache_WriteBack}, {input: QemuDiskCache_Unsafe}, {input: QemuDiskCache_DirectSync}, // Invalid - {input: "bla", err: true}, - {input: "invalid value", err: true}, - {input: "!@#$", err: true}, + {input: "bla", err: QemuDiskCache("").Error()}, + {input: "invalid value", err: QemuDiskCache("").Error()}, + {input: "!@#$", err: QemuDiskCache("").Error()}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From d1f36ec7fb793cde568b869bfddffade9221f310 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 17:54:15 +0000 Subject: [PATCH 070/191] test: match exact error --- proxmox/config_qemu_disk.go | 6 +++++- proxmox/config_qemu_disk_test.go | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index b8aec495..8112b0ca 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -493,12 +493,16 @@ const ( QemuDiskFormat_Raw QemuDiskFormat = "raw" ) +func (QemuDiskFormat) Error() error { + return fmt.Errorf("format can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) +} + func (format QemuDiskFormat) Validate() error { switch format { case QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw: return nil } - return fmt.Errorf("format can only be one of the following values: %s,%s,%s,%s,%s,%s,%s", QemuDiskFormat_Cow, QemuDiskFormat_Cloop, QemuDiskFormat_Qcow, QemuDiskFormat_Qcow2, QemuDiskFormat_Qed, QemuDiskFormat_Vmdk, QemuDiskFormat_Raw) + return QemuDiskFormat("").Error() } type QemuDiskSerial string diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 7814a7f3..ae990579 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -310,7 +310,7 @@ func Test_QemuDiskCache_Validate(t *testing.T) { func Test_QemuDiskFormat_Validate(t *testing.T) { testData := []struct { input QemuDiskFormat - err bool + err error }{ // Valid {input: QemuDiskFormat_Cow}, @@ -321,13 +321,13 @@ func Test_QemuDiskFormat_Validate(t *testing.T) { {input: QemuDiskFormat_Vmdk}, {input: QemuDiskFormat_Raw}, // Invalid - {input: "bla", err: true}, - {input: "invalid value", err: true}, - {input: "!@#$", err: true}, + {input: "bla", err: QemuDiskFormat("").Error()}, + {input: "invalid value", err: QemuDiskFormat("").Error()}, + {input: "!@#$", err: QemuDiskFormat("").Error()}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From d7b9fae8cc905f9f4b614f406d3374edfb2b852a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:15:29 +0000 Subject: [PATCH 071/191] refactor: make `0` default instad of `nil` --- proxmox/config_qemu_disk.go | 80 ++++++++---------- proxmox/config_qemu_disk_test.go | 138 ++++++++++++++----------------- 2 files changed, 96 insertions(+), 122 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 8112b0ca..575b46f7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -211,34 +211,34 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { // format // media - if disk.Bandwidth.Iops.ReadLimit.Concurrent != nil { - settings = settings + ",iops_rd=" + strconv.Itoa(int(*disk.Bandwidth.Iops.ReadLimit.Concurrent)) + if disk.Bandwidth.Iops.ReadLimit.Concurrent != 0 { + settings = settings + ",iops_rd=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Concurrent)) } - if disk.Bandwidth.Iops.ReadLimit.Burst != nil { - settings = settings + ",iops_rd_max=" + strconv.Itoa(int(*disk.Bandwidth.Iops.ReadLimit.Burst)) + if disk.Bandwidth.Iops.ReadLimit.Burst != 0 { + settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Burst)) } - if disk.Bandwidth.Iops.WriteLimit.Concurrent != nil { - settings = settings + ",iops_wr=" + strconv.Itoa(int(*disk.Bandwidth.Iops.WriteLimit.Concurrent)) + if disk.Bandwidth.Iops.WriteLimit.Concurrent != 0 { + settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Concurrent)) } - if disk.Bandwidth.Iops.WriteLimit.Burst != nil { - settings = settings + ",iops_wr_max=" + strconv.Itoa(int(*disk.Bandwidth.Iops.WriteLimit.Burst)) + if disk.Bandwidth.Iops.WriteLimit.Burst != 0 { + settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Burst)) } if (disk.Type == scsi || disk.Type == virtIO) && disk.IOThread { settings = settings + ",iothread=1" } - if disk.Bandwidth.Data.ReadLimit.Concurrent != nil { - settings = settings + fmt.Sprintf(",mbps_rd=%.2f", *disk.Bandwidth.Data.ReadLimit.Concurrent) + if disk.Bandwidth.Data.ReadLimit.Concurrent != 0 { + settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.Data.ReadLimit.Concurrent) } - if disk.Bandwidth.Data.ReadLimit.Burst != nil { - settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", *disk.Bandwidth.Data.ReadLimit.Burst) + if disk.Bandwidth.Data.ReadLimit.Burst != 0 { + settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.Data.ReadLimit.Burst) } - if disk.Bandwidth.Data.WriteLimit.Concurrent != nil { - settings = settings + fmt.Sprintf(",mbps_wr=%.2f", *disk.Bandwidth.Data.WriteLimit.Concurrent) + if disk.Bandwidth.Data.WriteLimit.Concurrent != 0 { + settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.Data.WriteLimit.Concurrent) } - if disk.Bandwidth.Data.WriteLimit.Burst != nil { - settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", *disk.Bandwidth.Data.WriteLimit.Burst) + if disk.Bandwidth.Data.WriteLimit.Burst != 0 { + settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.Data.WriteLimit.Burst) } if !disk.Replicate { @@ -304,23 +304,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "iops_rd" { tmp, _ := strconv.Atoi(e[1]) - pointer := uint(tmp) - disk.Bandwidth.Iops.ReadLimit.Concurrent = &pointer + disk.Bandwidth.Iops.ReadLimit.Concurrent = uint(tmp) } if e[0] == "iops_rd_max" { tmp, _ := strconv.Atoi(e[1]) - pointer := uint(tmp) - disk.Bandwidth.Iops.ReadLimit.Burst = &pointer + disk.Bandwidth.Iops.ReadLimit.Burst = uint(tmp) } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) - pointer := uint(tmp) - disk.Bandwidth.Iops.WriteLimit.Concurrent = &pointer + disk.Bandwidth.Iops.WriteLimit.Concurrent = uint(tmp) } if e[0] == "iops_wr_max" { tmp, _ := strconv.Atoi(e[1]) - pointer := uint(tmp) - disk.Bandwidth.Iops.WriteLimit.Burst = &pointer + disk.Bandwidth.Iops.WriteLimit.Burst = uint(tmp) } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) @@ -328,23 +324,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "mbps_rd" { tmp, _ := strconv.ParseFloat(e[1], 32) - pointer := float32(math.Round(tmp*100) / 100) - disk.Bandwidth.Data.ReadLimit.Concurrent = &pointer + disk.Bandwidth.Data.ReadLimit.Concurrent = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_rd_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - pointer := float32(math.Round(tmp*100) / 100) - disk.Bandwidth.Data.ReadLimit.Burst = &pointer + disk.Bandwidth.Data.ReadLimit.Burst = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr" { tmp, _ := strconv.ParseFloat(e[1], 32) - pointer := float32(math.Round(tmp*100) / 100) - disk.Bandwidth.Data.WriteLimit.Concurrent = &pointer + disk.Bandwidth.Data.WriteLimit.Concurrent = float32(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - pointer := float32(math.Round(tmp*100) / 100) - disk.Bandwidth.Data.WriteLimit.Burst = &pointer + disk.Bandwidth.Data.WriteLimit.Burst = float32(math.Round(tmp*100) / 100) } if e[0] == "replicate" { disk.Replicate, _ = strconv.ParseBool(e[1]) @@ -417,16 +409,16 @@ func (data QemuDiskBandwidthData) Validate() error { } type QemuDiskBandwidthDataLimit struct { - Burst *float32 // nil = default - Concurrent *float32 // nil = unlimited + Burst float32 // 0 = default + Concurrent float32 // 0 = unlimited } func (limit QemuDiskBandwidthDataLimit) Validate() error { - if limit.Burst != nil && *limit.Burst < 1 { - return errors.New("burst may not be lower then 1") + if limit.Burst != 0 && limit.Burst < 1 { + return errors.New("burst may not be lower then 1 except for 0") } - if limit.Concurrent != nil && *limit.Concurrent < 1 { - return errors.New("concurrent may not be lower then 1") + if limit.Concurrent != 0 && limit.Concurrent < 1 { + return errors.New("concurrent may not be lower then 1 except for 0") } return nil } @@ -445,16 +437,16 @@ func (iops QemuDiskBandwidthIops) Validate() error { } type QemuDiskBandwidthIopsLimit struct { - Burst *uint // nil = default - Concurrent *uint // nil = unlimited + Burst uint // 0 = default + Concurrent uint // 0 = unlimited } func (limit QemuDiskBandwidthIopsLimit) Validate() error { - if limit.Burst != nil && *limit.Burst < 10 { - return errors.New("burst may not be lower then 10") + if limit.Burst != 0 && limit.Burst < 10 { + return errors.New("burst may not be lower then 10 except for 0") } - if limit.Concurrent != nil && *limit.Concurrent < 10 { - return errors.New("concurrent may not be lower then 1") + if limit.Concurrent != 0 && limit.Concurrent < 10 { + return errors.New("concurrent may not be lower then 10 except for 0") } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index ae990579..45f25946 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -104,12 +104,6 @@ func Test_QemuDiskAsyncIO_Validate(t *testing.T) { } func Test_QemuDiskBandwidth_Validate(t *testing.T) { - float0 := float32(0) - float0a := float32(0.99) - float1 := float32(1) - uint0 := uint(0) - uint9 := uint(9) - uint10 := uint(10) testData := []struct { input QemuDiskBandwidth err bool @@ -118,35 +112,35 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { {input: QemuDiskBandwidth{}}, {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}, {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}, {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, // Invalid - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: true}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: true}, } for _, e := range testData { if e.err { @@ -158,9 +152,6 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { } func Test_QemuDiskBandwidthData_Validate(t *testing.T) { - float0 := float32(0) - float0a := float32(0.99) - float1 := float32(1) testData := []struct { input QemuDiskBandwidthData err bool @@ -168,20 +159,20 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { // Valid {input: QemuDiskBandwidthData{}}, {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float1}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float1}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, // Invalid - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}, err: true}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}, err: true}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}, err: true}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: &float0a}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: &float0a}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: true}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: true}, } for _, e := range testData { if e.err { @@ -193,22 +184,19 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { } func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { - float0 := float32(0) - float0a := float32(0.99) - float1 := float32(1) testData := []struct { input QemuDiskBandwidthDataLimit err bool }{ // Valid {input: QemuDiskBandwidthDataLimit{}}, - {input: QemuDiskBandwidthDataLimit{Burst: &float1}}, - {input: QemuDiskBandwidthDataLimit{Concurrent: &float1}}, + {input: QemuDiskBandwidthDataLimit{Burst: 0}}, + {input: QemuDiskBandwidthDataLimit{Burst: 1}}, + {input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, + {input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, // Invalid - {input: QemuDiskBandwidthDataLimit{Burst: &float0}, err: true}, - {input: QemuDiskBandwidthDataLimit{Burst: &float0a}, err: true}, - {input: QemuDiskBandwidthDataLimit{Concurrent: &float0}, err: true}, - {input: QemuDiskBandwidthDataLimit{Concurrent: &float0a}, err: true}, + {input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: true}, + {input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: true}, } for _, e := range testData { if e.err { @@ -220,9 +208,6 @@ func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { } func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { - uint0 := uint(0) - uint9 := uint(9) - uint10 := uint(10) testData := []struct { input QemuDiskBandwidthIops err bool @@ -230,20 +215,20 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { // Valid {input: QemuDiskBandwidthIops{}}, {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint10}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, // Invalid - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}, err: true}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}, err: true}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}, err: true}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint0}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: &uint9}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: true}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: true}, } for _, e := range testData { if e.err { @@ -255,22 +240,19 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { } func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { - uint0 := uint(0) - uint9 := uint(9) - uint10 := uint(10) testData := []struct { input QemuDiskBandwidthIopsLimit err bool }{ // Valid {input: QemuDiskBandwidthIopsLimit{}}, - {input: QemuDiskBandwidthIopsLimit{Burst: &uint10}}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint10}}, + {input: QemuDiskBandwidthIopsLimit{Burst: 0}}, + {input: QemuDiskBandwidthIopsLimit{Burst: 10}}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, // Invalid - {input: QemuDiskBandwidthIopsLimit{Burst: &uint0}, err: true}, - {input: QemuDiskBandwidthIopsLimit{Burst: &uint9}, err: true}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint0}, err: true}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: &uint9}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: true}, } for _, e := range testData { if e.err { From 25658bf0615593c0e2f65f03a283944465c0c510 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:22:07 +0000 Subject: [PATCH 072/191] test: match exact error --- proxmox/config_qemu_disk.go | 18 ++++++-- proxmox/config_qemu_disk_test.go | 71 ++++++++++++++++---------------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 575b46f7..f2430f50 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -413,12 +413,17 @@ type QemuDiskBandwidthDataLimit struct { Concurrent float32 // 0 = unlimited } +const ( + Error_QemuDiskBandwidthDataLimit_Burst string = "burst may not be lower then 1 except for 0" + Error_QemuDiskBandwidthDataLimit_Concurrent string = "concurrent may not be lower then 1 except for 0" +) + func (limit QemuDiskBandwidthDataLimit) Validate() error { if limit.Burst != 0 && limit.Burst < 1 { - return errors.New("burst may not be lower then 1 except for 0") + return errors.New(Error_QemuDiskBandwidthDataLimit_Burst) } if limit.Concurrent != 0 && limit.Concurrent < 1 { - return errors.New("concurrent may not be lower then 1 except for 0") + return errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) } return nil } @@ -441,12 +446,17 @@ type QemuDiskBandwidthIopsLimit struct { Concurrent uint // 0 = unlimited } +const ( + Error_QemuDiskBandwidthIopsLimit_Burst string = "burst may not be lower then 10 except for 0" + Error_QemuDiskBandwidthIopsLimit_Concurrent string = "concurrent may not be lower then 10 except for 0" +) + func (limit QemuDiskBandwidthIopsLimit) Validate() error { if limit.Burst != 0 && limit.Burst < 10 { - return errors.New("burst may not be lower then 10 except for 0") + return errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) } if limit.Concurrent != 0 && limit.Concurrent < 10 { - return errors.New("concurrent may not be lower then 10 except for 0") + return errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 45f25946..e991e73e 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -1,6 +1,7 @@ package proxmox import ( + "errors" "testing" "github.com/Telmate/proxmox-api-go/test/data/test_data_qemu" @@ -106,7 +107,7 @@ func Test_QemuDiskAsyncIO_Validate(t *testing.T) { func Test_QemuDiskBandwidth_Validate(t *testing.T) { testData := []struct { input QemuDiskBandwidth - err bool + err error }{ // Valid {input: QemuDiskBandwidth{}}, @@ -133,18 +134,18 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, // Invalid - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: true}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: true}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: true}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } @@ -154,7 +155,7 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { func Test_QemuDiskBandwidthData_Validate(t *testing.T) { testData := []struct { input QemuDiskBandwidthData - err bool + err error }{ // Valid {input: QemuDiskBandwidthData{}}, @@ -169,14 +170,14 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, // Invalid - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: true}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: true}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: true}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } @@ -186,7 +187,7 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { testData := []struct { input QemuDiskBandwidthDataLimit - err bool + err error }{ // Valid {input: QemuDiskBandwidthDataLimit{}}, @@ -195,12 +196,12 @@ func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { {input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, {input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, // Invalid - {input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: true}, - {input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: true}, + {input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } @@ -210,7 +211,7 @@ func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { testData := []struct { input QemuDiskBandwidthIops - err bool + err error }{ // Valid {input: QemuDiskBandwidthIops{}}, @@ -225,14 +226,14 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, // Invalid - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: true}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: true}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: true}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } @@ -242,7 +243,7 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { testData := []struct { input QemuDiskBandwidthIopsLimit - err bool + err error }{ // Valid {input: QemuDiskBandwidthIopsLimit{}}, @@ -251,12 +252,12 @@ func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { {input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, {input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, // Invalid - {input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: true}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: true}, + {input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From fa66b8b45b6e2329c891d53e1a205bd3703343c5 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:26:25 +0000 Subject: [PATCH 073/191] test: match exact error --- proxmox/config_qemu_disk.go | 9 +++++++-- proxmox/config_qemu_disk_test.go | 14 +++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f2430f50..6dfbffee 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -16,12 +16,17 @@ type IsoFile struct { Size string `json:"size"` } +const ( + Error_IsoFile_File string = "file may not be empty" + Error_IsoFile_Storage string = "storage may not be empty" +) + func (iso IsoFile) Validate() error { if iso.File == "" { - return errors.New("file may not be empty") + return errors.New(Error_IsoFile_File) } if iso.Storage == "" { - return errors.New("storage may not be empty") + return errors.New(Error_IsoFile_Storage) } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index e991e73e..da75e66d 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -11,19 +11,19 @@ import ( func Test_IsoFile_Validate(t *testing.T) { testData := []struct { input IsoFile - err bool + err error }{ // Valid {input: IsoFile{File: "anything", Storage: "something"}}, // Invalid - {input: IsoFile{}, err: true}, - {input: IsoFile{File: "anything"}, err: true}, - {input: IsoFile{Storage: "something"}, err: true}, - {input: IsoFile{Size: "something"}, err: true}, + {input: IsoFile{}, err: errors.New(Error_IsoFile_File)}, + {input: IsoFile{File: "anything"}, err: errors.New(Error_IsoFile_Storage)}, + {input: IsoFile{Storage: "something"}, err: errors.New(Error_IsoFile_File)}, + {input: IsoFile{Size: "something"}, err: errors.New(Error_IsoFile_File)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From 70f05b03c0cfb5371c5396f7fe5b16bf91064c24 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:30:27 +0000 Subject: [PATCH 074/191] test: match exact error --- proxmox/config_qemu_disk.go | 6 +++++- proxmox/config_qemu_disk_test.go | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 6dfbffee..72b71c02 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -37,6 +37,10 @@ type QemuCdRom struct { Passthrough bool `json:"passthrough,omitempty"` } +const ( + Error_QemuCdRom_MutuallyExclusive string = "iso and passthrough are mutually exclusive" +) + // TODO write test func (cdRom QemuCdRom) mapToApiValues() string { if cdRom.Passthrough { @@ -68,7 +72,7 @@ func (cdRom QemuCdRom) Validate() error { return err } if cdRom.Passthrough { - return errors.New("iso and passthrough are mutually exclusive") + return errors.New(Error_QemuCdRom_MutuallyExclusive) } } return nil diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index da75e66d..6b46034b 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -33,22 +33,22 @@ func Test_IsoFile_Validate(t *testing.T) { func Test_QemuCdRom_Validate(t *testing.T) { testData := []struct { input QemuCdRom - err bool + err error }{ // Valid {input: QemuCdRom{}}, {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "Something"}}}, {input: QemuCdRom{Passthrough: true}}, // Invalid - {input: QemuCdRom{Iso: &IsoFile{}}, err: true}, - {input: QemuCdRom{Iso: &IsoFile{File: "anything"}}, err: true}, - {input: QemuCdRom{Iso: &IsoFile{Storage: "something"}}, err: true}, - {input: QemuCdRom{Iso: &IsoFile{Size: "something"}}, err: true}, - {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "something"}, Passthrough: true}, err: true}, + {input: QemuCdRom{Iso: &IsoFile{}}, err: errors.New(Error_IsoFile_File)}, + {input: QemuCdRom{Iso: &IsoFile{File: "anything"}}, err: errors.New(Error_IsoFile_Storage)}, + {input: QemuCdRom{Iso: &IsoFile{Storage: "something"}}, err: errors.New(Error_IsoFile_File)}, + {input: QemuCdRom{Iso: &IsoFile{Size: "something"}}, err: errors.New(Error_IsoFile_File)}, + {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "something"}, Passthrough: true}, err: errors.New(Error_QemuCdRom_MutuallyExclusive)}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From 3ee90fca25a8f50fbef91873f0d0c3b137f27023 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:35:19 +0000 Subject: [PATCH 075/191] test: match exact error --- proxmox/config_qemu_disk.go | 6 +++++- proxmox/config_qemu_disk_test.go | 19 ++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 72b71c02..af8aa555 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -143,6 +143,10 @@ type QemuCloudInitDisk struct { Storage string `json:"storage,omitempty"` } +const ( + Error_QemuCloudInitDisk_Storage string = "storage should not be empty" +) + // TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { return cloudInit.Storage + ":cloudinit,format=" + string(cloudInit.Format) @@ -160,7 +164,7 @@ func (cloudInit QemuCloudInitDisk) Validate() error { return err } if cloudInit.Storage == "" { - return errors.New("storage should not be empty") + return errors.New(Error_QemuCloudInitDisk_Storage) } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 6b46034b..66c44ab2 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -56,24 +56,21 @@ func Test_QemuCdRom_Validate(t *testing.T) { } func Test_QemuCloudInitDisk_Validate(t *testing.T) { - formatRaw := QemuDiskFormat_Raw - formatEmpty := QemuDiskFormat("") - formatInvalid := QemuDiskFormat("invalid") testData := []struct { input QemuCloudInitDisk - err bool + err error }{ // Valid - {input: QemuCloudInitDisk{Storage: "anything", Format: formatRaw}}, + {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat_Raw}}, // Invalid - {input: QemuCloudInitDisk{}, err: true}, - {input: QemuCloudInitDisk{Format: formatRaw}, err: true}, - {input: QemuCloudInitDisk{Storage: "anything", Format: formatEmpty}, err: true}, - {input: QemuCloudInitDisk{Storage: "anything", Format: formatInvalid}, err: true}, + {input: QemuCloudInitDisk{}, err: QemuDiskFormat("").Error()}, + {input: QemuCloudInitDisk{Format: QemuDiskFormat_Raw}, err: errors.New(Error_QemuCloudInitDisk_Storage)}, + {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("")}, err: QemuDiskFormat("").Error()}, + {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("invalid")}, err: QemuDiskFormat("").Error()}, } for _, e := range testData { - if e.err { - require.Error(t, e.input.Validate()) + if e.err != nil { + require.Equal(t, e.input.Validate(), e.err) } else { require.NoError(t, e.input.Validate()) } From 5e46b85ad4ba3829292b40e678877f056d15a264 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:39:54 +0000 Subject: [PATCH 076/191] refactor: create const for errors --- proxmox/config_qemu_disk.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index af8aa555..ddd53f7a 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -522,15 +522,20 @@ func (format QemuDiskFormat) Validate() error { type QemuDiskSerial string +const ( + Error_QemuDiskSerial_IllegalCharacter string = "serial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_" + Error_QemuDiskSerial_IllegalLength string = "serial may only be 60 characters long" +) + // QemuDiskSerial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ // And has a max length of 60 characters func (serial QemuDiskSerial) Validate() error { regex, _ := regexp.Compile(`^([a-z]|[A-Z]|[0-9]|_|-)*$`) if !regex.Match([]byte(serial)) { - return errors.New("serial may only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_") + return errors.New(Error_QemuDiskSerial_IllegalCharacter) } if len(serial) > 60 { - return errors.New("serial may only be 60 characters long") + return errors.New(Error_QemuDiskSerial_IllegalLength) } return nil } From ab1df9549c183bb219ddc8ff5d67f715ab85e120 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 15 Mar 2023 20:32:58 +0000 Subject: [PATCH 077/191] test: name all test cases --- proxmox/config_qemu_disk_test.go | 418 +++++++++++++++++-------------- 1 file changed, 229 insertions(+), 189 deletions(-) diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 66c44ab2..99de3fdb 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -2,6 +2,7 @@ package proxmox import ( "errors" + "fmt" "testing" "github.com/Telmate/proxmox-api-go/test/data/test_data_qemu" @@ -10,307 +11,340 @@ import ( func Test_IsoFile_Validate(t *testing.T) { testData := []struct { + name string input IsoFile err error }{ // Valid - {input: IsoFile{File: "anything", Storage: "something"}}, + {name: "Valid 00", input: IsoFile{File: "anything", Storage: "something"}}, // Invalid - {input: IsoFile{}, err: errors.New(Error_IsoFile_File)}, - {input: IsoFile{File: "anything"}, err: errors.New(Error_IsoFile_Storage)}, - {input: IsoFile{Storage: "something"}, err: errors.New(Error_IsoFile_File)}, - {input: IsoFile{Size: "something"}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 00", input: IsoFile{}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 01", input: IsoFile{File: "anything"}, err: errors.New(Error_IsoFile_Storage)}, + {name: "Invalid 02", input: IsoFile{Storage: "something"}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 03", input: IsoFile{Size: "something"}, err: errors.New(Error_IsoFile_File)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuCdRom_Validate(t *testing.T) { testData := []struct { + name string input QemuCdRom err error }{ // Valid - {input: QemuCdRom{}}, - {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "Something"}}}, - {input: QemuCdRom{Passthrough: true}}, + {name: "Valid 00", input: QemuCdRom{}}, + {name: "Valid 01", input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "Something"}}}, + {name: "Valid 02", input: QemuCdRom{Passthrough: true}}, // Invalid - {input: QemuCdRom{Iso: &IsoFile{}}, err: errors.New(Error_IsoFile_File)}, - {input: QemuCdRom{Iso: &IsoFile{File: "anything"}}, err: errors.New(Error_IsoFile_Storage)}, - {input: QemuCdRom{Iso: &IsoFile{Storage: "something"}}, err: errors.New(Error_IsoFile_File)}, - {input: QemuCdRom{Iso: &IsoFile{Size: "something"}}, err: errors.New(Error_IsoFile_File)}, - {input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "something"}, Passthrough: true}, err: errors.New(Error_QemuCdRom_MutuallyExclusive)}, + {name: "Invalid 00", input: QemuCdRom{Iso: &IsoFile{}}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 01", input: QemuCdRom{Iso: &IsoFile{File: "anything"}}, err: errors.New(Error_IsoFile_Storage)}, + {name: "Invalid 02", input: QemuCdRom{Iso: &IsoFile{Storage: "something"}}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 03", input: QemuCdRom{Iso: &IsoFile{Size: "something"}}, err: errors.New(Error_IsoFile_File)}, + {name: "Invalid 04", input: QemuCdRom{Iso: &IsoFile{File: "anything", Storage: "something"}, Passthrough: true}, err: errors.New(Error_QemuCdRom_MutuallyExclusive)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuCloudInitDisk_Validate(t *testing.T) { testData := []struct { + name string input QemuCloudInitDisk err error }{ // Valid - {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat_Raw}}, + {name: "Valid 00", input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat_Raw}}, // Invalid - {input: QemuCloudInitDisk{}, err: QemuDiskFormat("").Error()}, - {input: QemuCloudInitDisk{Format: QemuDiskFormat_Raw}, err: errors.New(Error_QemuCloudInitDisk_Storage)}, - {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("")}, err: QemuDiskFormat("").Error()}, - {input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("invalid")}, err: QemuDiskFormat("").Error()}, + {name: "Invalid 00", input: QemuCloudInitDisk{}, err: QemuDiskFormat("").Error()}, + {name: "Invalid 01", input: QemuCloudInitDisk{Format: QemuDiskFormat_Raw}, err: errors.New(Error_QemuCloudInitDisk_Storage)}, + {name: "Invalid 02", input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("")}, err: QemuDiskFormat("").Error()}, + {name: "Invalid 03", input: QemuCloudInitDisk{Storage: "anything", Format: QemuDiskFormat("invalid")}, err: QemuDiskFormat("").Error()}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskAsyncIO err error }{ // Valid - {input: ""}, - {input: QemuDiskAsyncIO_Native}, - {input: QemuDiskAsyncIO_Threads}, - {input: QemuDiskAsyncIO_IOuring}, + {name: "Valid 00", input: ""}, + {name: "Valid 01", input: QemuDiskAsyncIO_Native}, + {name: "Valid 02", input: QemuDiskAsyncIO_Threads}, + {name: "Valid 03", input: QemuDiskAsyncIO_IOuring}, // Invalid - {input: "bla", err: QemuDiskAsyncIO("").Error()}, - {input: "invalid value", err: QemuDiskAsyncIO("").Error()}, - {input: "!@#$", err: QemuDiskAsyncIO("").Error()}, + {name: "Invalid 00", input: "bla", err: QemuDiskAsyncIO("").Error()}, + {name: "Invalid 01", input: "invalid value", err: QemuDiskAsyncIO("").Error()}, + {name: "Invalid 02", input: "!@#$", err: QemuDiskAsyncIO("").Error()}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskBandwidth_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskBandwidth err error }{ // Valid - {input: QemuDiskBandwidth{}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, + {name: "Valid 00", input: QemuDiskBandwidth{}}, + {name: "Valid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}, + {name: "Valid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}, + {name: "Valid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, + {name: "Valid 04", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, + {name: "Valid 05", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, + {name: "Valid 06", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, + {name: "Valid 07", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}, + {name: "Valid 08", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, + {name: "Valid 09", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, + {name: "Valid 10", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, + {name: "Valid 11", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, + {name: "Valid 12", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}, + {name: "Valid 13", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}, + {name: "Valid 14", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, + {name: "Valid 15", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, + {name: "Valid 16", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, + {name: "Valid 17", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, + {name: "Valid 18", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}, + {name: "Valid 19", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, + {name: "Valid 20", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}}, + {name: "Valid 21", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, + {name: "Valid 22", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, // Invalid - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {name: "Invalid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {name: "Invalid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 04", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {name: "Invalid 05", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 06", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {name: "Invalid 07", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskBandwidthData_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskBandwidthData err error }{ // Valid - {input: QemuDiskBandwidthData{}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, + {name: "Valid 00", input: QemuDiskBandwidthData{}}, + {name: "Valid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}, + {name: "Valid 02", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, + {name: "Valid 03", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, + {name: "Valid 04", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, + {name: "Valid 05", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, + {name: "Valid 06", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}, + {name: "Valid 07", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, + {name: "Valid 08", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, + {name: "Valid 09", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, + {name: "Valid 10", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, // Invalid - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {name: "Invalid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {name: "Invalid 03", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskBandwidthDataLimit err error }{ // Valid - {input: QemuDiskBandwidthDataLimit{}}, - {input: QemuDiskBandwidthDataLimit{Burst: 0}}, - {input: QemuDiskBandwidthDataLimit{Burst: 1}}, - {input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, - {input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, + {name: "Valid 00", input: QemuDiskBandwidthDataLimit{}}, + {name: "Valid 01", input: QemuDiskBandwidthDataLimit{Burst: 0}}, + {name: "Valid 02", input: QemuDiskBandwidthDataLimit{Burst: 1}}, + {name: "Valid 03", input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, + {name: "Valid 04", input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, // Invalid - {input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, + {name: "Invalid 01", input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskBandwidthIops err error }{ // Valid - {input: QemuDiskBandwidthIops{}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + {name: "Valid 00", input: QemuDiskBandwidthIops{}}, + {name: "Valid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, + {name: "Valid 02", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 03", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 04", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {name: "Valid 05", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + {name: "Valid 06", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, + {name: "Valid 07", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}, + {name: "Valid 08", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 09", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {name: "Valid 10", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, // Invalid - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {name: "Invalid 03", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskBandwidthIopsLimit err error }{ // Valid - {input: QemuDiskBandwidthIopsLimit{}}, - {input: QemuDiskBandwidthIopsLimit{Burst: 0}}, - {input: QemuDiskBandwidthIopsLimit{Burst: 10}}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, + {name: "Valid 00", input: QemuDiskBandwidthIopsLimit{}}, + {name: "Valid 01", input: QemuDiskBandwidthIopsLimit{Burst: 0}}, + {name: "Valid 02", input: QemuDiskBandwidthIopsLimit{Burst: 10}}, + {name: "Valid 03", input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, + {name: "Valid 04", input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, // Invalid - {input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskCache_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskCache err error }{ // Valid - {input: ""}, - {input: QemuDiskCache_None}, - {input: QemuDiskCache_WriteThrough}, - {input: QemuDiskCache_WriteBack}, - {input: QemuDiskCache_Unsafe}, - {input: QemuDiskCache_DirectSync}, + {name: "Valid 00", input: ""}, + {name: "Valid 01", input: QemuDiskCache_None}, + {name: "Valid 02", input: QemuDiskCache_WriteThrough}, + {name: "Valid 03", input: QemuDiskCache_WriteBack}, + {name: "Valid 04", input: QemuDiskCache_Unsafe}, + {name: "Valid 05", input: QemuDiskCache_DirectSync}, // Invalid - {input: "bla", err: QemuDiskCache("").Error()}, - {input: "invalid value", err: QemuDiskCache("").Error()}, - {input: "!@#$", err: QemuDiskCache("").Error()}, + {name: "Invalid 00", input: "bla", err: QemuDiskCache("").Error()}, + {name: "Invalid 01", input: "invalid value", err: QemuDiskCache("").Error()}, + {name: "Invalid 02", input: "!@#$", err: QemuDiskCache("").Error()}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } func Test_QemuDiskFormat_Validate(t *testing.T) { testData := []struct { + name string input QemuDiskFormat err error }{ // Valid - {input: QemuDiskFormat_Cow}, - {input: QemuDiskFormat_Cloop}, - {input: QemuDiskFormat_Qcow}, - {input: QemuDiskFormat_Qcow2}, - {input: QemuDiskFormat_Qed}, - {input: QemuDiskFormat_Vmdk}, - {input: QemuDiskFormat_Raw}, + {name: "Valid 00", input: QemuDiskFormat_Cow}, + {name: "Valid 01", input: QemuDiskFormat_Cloop}, + {name: "Valid 02", input: QemuDiskFormat_Qcow}, + {name: "Valid 03", input: QemuDiskFormat_Qcow2}, + {name: "Valid 04", input: QemuDiskFormat_Qed}, + {name: "Valid 05", input: QemuDiskFormat_Vmdk}, + {name: "Valid 06", input: QemuDiskFormat_Raw}, // Invalid - {input: "bla", err: QemuDiskFormat("").Error()}, - {input: "invalid value", err: QemuDiskFormat("").Error()}, - {input: "!@#$", err: QemuDiskFormat("").Error()}, + {name: "Invalid 00", input: "bla", err: QemuDiskFormat("").Error()}, + {name: "Invalid 01", input: "invalid value", err: QemuDiskFormat("").Error()}, + {name: "Invalid 02", input: "!@#$", err: QemuDiskFormat("").Error()}, } - for _, e := range testData { - if e.err != nil { - require.Equal(t, e.input.Validate(), e.err) - } else { - require.NoError(t, e.input.Validate()) - } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) } } @@ -322,10 +356,16 @@ func Test_QemuDiskSerial_Validate(t *testing.T) { legal: test_data_qemu.QemuDiskSerial_Legal(), illegal: test_data_qemu.QemuDiskSerial_Illegal(), } - for _, e := range testRunes.legal { - require.NoError(t, QemuDiskSerial(e).Validate()) + for i, test := range testRunes.legal { + name := fmt.Sprintf("legal%03d", i) + t.Run(name, func(*testing.T) { + require.NoError(t, QemuDiskSerial(test).Validate(), name) + }) } - for _, e := range testRunes.illegal { - require.Error(t, QemuDiskSerial(e).Validate()) + for i, test := range testRunes.illegal { + name := fmt.Sprintf("illegal%03d", i) + t.Run(name, func(*testing.T) { + require.Error(t, QemuDiskSerial(test).Validate(), name) + }) } } From 8ac0792d3a4be77fa2c4652d14e27feb4a5ae4f6 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:16:22 +0000 Subject: [PATCH 078/191] feat: add Validat func for `ConfigQemu.Disks` --- proxmox/config_qemu.go | 20 + proxmox/config_qemu_disk.go | 75 ++ proxmox/config_qemu_disk_ide.go | 66 ++ proxmox/config_qemu_disk_sata.go | 66 ++ proxmox/config_qemu_disk_scsi.go | 66 ++ proxmox/config_qemu_disk_virtio.go | 66 ++ proxmox/config_qemu_test.go | 1186 ++++++++++++++++++++++++++++ 7 files changed, 1545 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 602bacf8..9ce0041f 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -93,6 +93,10 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { if err != nil { return } + err = config.Validate() + if err != nil { + return + } params, _, err := config.mapToApiValues(ConfigQemu{}) if err != nil { return @@ -638,6 +642,10 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef if err != nil { return } + err = newConfig.Validate() + if err != nil { + return + } params, markedDisks, err := newConfig.mapToApiValues(*currentConfig) if err != nil { return @@ -681,6 +689,18 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef return } +func (config ConfigQemu) Validate() (err error) { + // TODO test all other use cases + if config.Disks != nil { + err = config.Disks.Validate() + if err != nil { + return + } + } + + return +} + // HasCloudInit - are there cloud-init options? func (config ConfigQemu) HasCloudInit() bool { for _, config := range config.Ipconfig { diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index ddd53f7a..536d7f6e 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -192,6 +192,13 @@ type qemuDisk struct { Type qemuDiskType } +const ( + Error_QemuDisk_File string = "file may not be empty" + Error_QemuDisk_MutuallyExclusive string = "settings cdrom,cloudinit,disk,passthrough are mutually exclusive" + Error_QemuDisk_Size string = "size must be greater then 0" + Error_QemuDisk_Storage string = "storage may not be empty" +) + // TODO write test func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { if disk.Storage != "" { @@ -375,6 +382,42 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { return &disk } +func (disk *qemuDisk) validate() (err error) { + if disk == nil { + return + } + if err = disk.AsyncIO.Validate(); err != nil { + return + } + if err = disk.Bandwidth.Validate(); err != nil { + return + } + if err = disk.Cache.Validate(); err != nil { + return + } + if err = disk.Serial.Validate(); err != nil { + return + } + if disk.Disk { + // disk + if err = disk.Format.Validate(); err != nil { + return + } + if disk.Size == 0 { + return errors.New(Error_QemuDisk_Size) + } + if disk.Storage == "" { + return errors.New(Error_QemuDisk_Storage) + } + } else { + // passthrough + if disk.File == "" { + return errors.New(Error_QemuDisk_File) + } + } + return +} + type QemuDiskAsyncIO string const ( @@ -701,8 +744,40 @@ func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID return changes } +func (storages QemuStorages) Validate() (err error) { + if storages.Ide != nil { + err = storages.Ide.Validate() + if err != nil { + return + } + } + if storages.Sata != nil { + err = storages.Sata.Validate() + if err != nil { + return + } + } + if storages.Scsi != nil { + err = storages.Scsi.Validate() + if err != nil { + return + } + } + if storages.VirtIO != nil { + err = storages.VirtIO.Validate() + } + return +} + type qemuUpdateChanges struct { Delete string Move []qemuDiskShort Resize []qemuDiskResize } + +func diskSubtypeSet(set bool) error { + if set { + return errors.New(Error_QemuDisk_MutuallyExclusive) + } + return nil +} diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index e8b2ec8d..69c801be 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -36,6 +36,10 @@ func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { } } +func (disk QemuIdeDisk) Validate() error { + return disk.convertDataStructure().validate() +} + type QemuIdeDisks struct { Disk_0 *QemuIdeStorage `json:"0,omitempty"` Disk_1 *QemuIdeStorage `json:"1,omitempty"` @@ -91,6 +95,19 @@ func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { return nil } +func (disks QemuIdeDisks) Validate() error { + diskMap := disks.mapToIntMap() + for _, e := range diskMap { + if e != nil { + err := e.Validate() + if err != nil { + return err + } + } + } + return nil +} + type QemuIdePassthrough struct { AsyncIO QemuDiskAsyncIO Backup bool @@ -119,6 +136,10 @@ func (passthrough *QemuIdePassthrough) convertDataStructure() *qemuDisk { } } +func (passthrough QemuIdePassthrough) Validate() error { + return passthrough.convertDataStructure().validate() +} + type QemuIdeStorage struct { CdRom *QemuCdRom `json:"cdrom,omitempty"` CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` @@ -190,3 +211,48 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { Size: tmpDisk.Size, }} } + +func (storage QemuIdeStorage) Validate() (err error) { + // First check if more than one item is nil + var subTypeSet bool + if storage.CdRom != nil { + subTypeSet = true + } + if storage.CloudInit != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Disk != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Passthrough != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + } + // Validate sub items + if storage.CdRom != nil { + if err = storage.CdRom.Validate(); err != nil { + return + } + } + if storage.CloudInit != nil { + if err = storage.CloudInit.Validate(); err != nil { + return + } + } + if storage.Disk != nil { + if err = storage.Disk.Validate(); err != nil { + return + } + } + if storage.Passthrough != nil { + err = storage.Passthrough.Validate() + } + return +} diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index d8f30216..69759d8e 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -36,6 +36,10 @@ func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { } } +func (disk QemuSataDisk) Validate() error { + return disk.convertDataStructure().validate() +} + type QemuSataDisks struct { Disk_0 *QemuSataStorage `json:"0,omitempty"` Disk_1 *QemuSataStorage `json:"1,omitempty"` @@ -103,6 +107,19 @@ func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { return nil } +func (disks QemuSataDisks) Validate() error { + diskMap := disks.mapToIntMap() + for _, e := range diskMap { + if e != nil { + err := e.Validate() + if err != nil { + return err + } + } + } + return nil +} + type QemuSataPassthrough struct { AsyncIO QemuDiskAsyncIO Backup bool @@ -131,6 +148,10 @@ func (passthrough *QemuSataPassthrough) convertDataStructure() *qemuDisk { } } +func (passthrough QemuSataPassthrough) Validate() error { + return passthrough.convertDataStructure().validate() +} + type QemuSataStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -202,3 +223,48 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { Size: tmpDisk.Size, }} } + +func (storage *QemuSataStorage) Validate() (err error) { + // First check if more than one item is nil + var subTypeSet bool + if storage.CdRom != nil { + subTypeSet = true + } + if storage.CloudInit != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Disk != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Passthrough != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + } + // Validate sub items + if storage.CdRom != nil { + if err = storage.CdRom.Validate(); err != nil { + return + } + } + if storage.CloudInit != nil { + if err = storage.CloudInit.Validate(); err != nil { + return + } + } + if storage.Disk != nil { + if err = storage.Disk.Validate(); err != nil { + return + } + } + if storage.Passthrough != nil { + err = storage.Passthrough.Validate() + } + return +} diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 964a5752..851dc1e6 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -40,6 +40,10 @@ func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { } } +func (disk QemuScsiDisk) Validate() error { + return disk.convertDataStructure().validate() +} + type QemuScsiDisks struct { Disk_0 *QemuScsiStorage `json:"0,omitempty"` Disk_1 *QemuScsiStorage `json:"1,omitempty"` @@ -257,6 +261,19 @@ func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { return nil } +func (disks QemuScsiDisks) Validate() error { + diskMap := disks.mapToIntMap() + for _, e := range diskMap { + if e != nil { + err := e.Validate() + if err != nil { + return err + } + } + } + return nil +} + type QemuScsiPassthrough struct { AsyncIO QemuDiskAsyncIO Backup bool @@ -289,6 +306,10 @@ func (passthrough *QemuScsiPassthrough) convertDataStructure() *qemuDisk { } } +func (passthrough QemuScsiPassthrough) Validate() error { + return passthrough.convertDataStructure().validate() +} + type QemuScsiStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -364,3 +385,48 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { Size: tmpDisk.Size, }} } + +func (storage *QemuScsiStorage) Validate() (err error) { + // First check if more than one item is nil + var subTypeSet bool + if storage.CdRom != nil { + subTypeSet = true + } + if storage.CloudInit != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Disk != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Passthrough != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + } + // Validate sub items + if storage.CdRom != nil { + if err = storage.CdRom.Validate(); err != nil { + return + } + } + if storage.CloudInit != nil { + if err = storage.CloudInit.Validate(); err != nil { + return + } + } + if storage.Disk != nil { + if err = storage.Disk.Validate(); err != nil { + return + } + } + if storage.Passthrough != nil { + err = storage.Passthrough.Validate() + } + return +} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 2e041885..a16ab105 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -38,6 +38,10 @@ func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { } } +func (disk QemuVirtIODisk) Validate() error { + return disk.convertDataStructure().validate() +} + type QemuVirtIODisks struct { Disk_0 *QemuVirtIOStorage `json:"0,omitempty"` Disk_1 *QemuVirtIOStorage `json:"1,omitempty"` @@ -165,6 +169,19 @@ func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODis return nil } +func (disks QemuVirtIODisks) Validate() error { + diskMap := disks.mapToIntMap() + for _, e := range diskMap { + if e != nil { + err := e.Validate() + if err != nil { + return err + } + } + } + return nil +} + type QemuVirtIOPassthrough struct { AsyncIO QemuDiskAsyncIO Backup bool @@ -193,6 +210,10 @@ func (passthrough *QemuVirtIOPassthrough) convertDataStructure() *qemuDisk { } } +func (passthrough QemuVirtIOPassthrough) Validate() error { + return passthrough.convertDataStructure().validate() +} + type QemuVirtIOStorage struct { CdRom *QemuCdRom CloudInit *QemuCloudInitDisk @@ -265,3 +286,48 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { Size: tmpDisk.Size, }} } + +func (storage QemuVirtIOStorage) Validate() (err error) { + // First check if more than one item is nil + var subTypeSet bool + if storage.CdRom != nil { + subTypeSet = true + } + if storage.CloudInit != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Disk != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + subTypeSet = true + } + if storage.Passthrough != nil { + if err = diskSubtypeSet(subTypeSet); err != nil { + return + } + } + // Validate sub items + if storage.CdRom != nil { + if err = storage.CdRom.Validate(); err != nil { + return + } + } + if storage.CloudInit != nil { + if err = storage.CloudInit.Validate(); err != nil { + return + } + } + if storage.Disk != nil { + if err = storage.Disk.Validate(); err != nil { + return + } + } + if storage.Passthrough != nil { + err = storage.Passthrough.Validate() + } + return +} diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 9ac99e58..ad8bfd0f 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -1,12 +1,1198 @@ package proxmox import ( + "errors" "strings" "testing" + "github.com/Telmate/proxmox-api-go/test/data/test_data_qemu" "github.com/stretchr/testify/require" ) +func Test_ConfigQemu_Validate(t *testing.T) { + BandwidthValid0 := QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{ + Burst: 0, + Concurrent: 0, + }, + WriteLimit: QemuDiskBandwidthDataLimit{ + Burst: 0, + Concurrent: 0, + }, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{ + Burst: 0, + Concurrent: 0, + }, + WriteLimit: QemuDiskBandwidthIopsLimit{ + Burst: 0, + Concurrent: 0, + }, + }, + } + BandwidthValid1 := QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{ + Burst: 1, + Concurrent: 1, + }, + WriteLimit: QemuDiskBandwidthDataLimit{ + Burst: 1, + Concurrent: 1, + }, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{ + Burst: 10, + Concurrent: 10, + }, + WriteLimit: QemuDiskBandwidthIopsLimit{ + Burst: 10, + Concurrent: 10, + }, + }, + } + BandwidthValid2 := QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{ + Burst: 1, + Concurrent: 0, + }, + WriteLimit: QemuDiskBandwidthDataLimit{ + Burst: 1, + Concurrent: 0, + }, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{ + Burst: 10, + Concurrent: 0, + }, + WriteLimit: QemuDiskBandwidthIopsLimit{ + Burst: 10, + Concurrent: 0, + }, + }, + } + BandwidthValid3 := QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{ + Burst: 0, + Concurrent: 1, + }, + WriteLimit: QemuDiskBandwidthDataLimit{ + Burst: 0, + Concurrent: 1, + }, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{ + Burst: 0, + Concurrent: 10, + }, + WriteLimit: QemuDiskBandwidthIopsLimit{ + Burst: 0, + Concurrent: 10, + }, + }, + } + testData := []struct { + name string + input ConfigQemu + err error + }{ + // Valid + // Valid Disks + {name: "Valid Disks Empty 0", + input: ConfigQemu{Disks: &QemuStorages{}}, + }, + {name: "Valid Disks Empty 1", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}, + }}, + }, + // Valid Disks CdRom + {name: "Valid Disks CdRom", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{}}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}}}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}}}}, + }}, + }, + // Valid Disks CloudInit + {name: "Valid Disks CloudInit", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, + }}, + }, + // Valid Disks Disk + {name: "Valid Disks Disk", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Bandwidth: BandwidthValid0, + Cache: QemuDiskCache_DirectSync, + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "test", + }}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Bandwidth: BandwidthValid1, + Cache: QemuDiskCache_None, + Format: QemuDiskFormat_Cow, + Size: 1, + Storage: "test", + }}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Threads, + Bandwidth: BandwidthValid2, + Cache: QemuDiskCache_WriteBack, + Format: QemuDiskFormat_Qcow2, + Size: 10, + Storage: "test", + }}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: "", + Bandwidth: BandwidthValid3, + Cache: "", + Format: QemuDiskFormat_Vmdk, + Size: 1024, + Storage: "test", + }}}, + }}, + }, + // Valid Disks Passthrough + {name: "Valid Disks Passthrough", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Bandwidth: BandwidthValid3, + Cache: QemuDiskCache_DirectSync, + File: "test", + }}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + Bandwidth: BandwidthValid2, + Cache: "", + File: "test", + }}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Bandwidth: BandwidthValid1, + Cache: QemuDiskCache_WriteBack, + File: "test", + }}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: "", + Bandwidth: BandwidthValid0, + Cache: QemuDiskCache_WriteThrough, + File: "test", + }}}, + }}, + }, + // Invalid + // Invalid Disks Mutually exclusive Ide + {name: "Invalid Disks MutuallyExclusive Ide 0", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 1", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuIdeDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 2", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 3", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuIdeDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 4", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{ + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 5", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{ + Disk: &QemuIdeDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 6", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuIdeDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 7", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuIdeDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 8", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuIdeDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 9", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Ide 10", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuIdeDisk{}, + Passthrough: &QemuIdePassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + // Invalid Disks Mutually exclusive Sata + {name: "Invalid Disks MutuallyExclusive Sata 0", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 1", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuSataDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 2", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 3", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuSataDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 4", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{ + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 5", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{ + Disk: &QemuSataDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 6", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuSataDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 7", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuSataDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 8", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuSataDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 9", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Sata 10", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuSataDisk{}, + Passthrough: &QemuSataPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + // Invalid Disks Mutually exclusive Scsi + {name: "Invalid Disks MutuallyExclusive Scsi 0", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 1", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuScsiDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 2", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 3", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuScsiDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 4", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{ + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 5", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{ + Disk: &QemuScsiDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 6", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuScsiDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 7", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuScsiDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 8", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuScsiDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 9", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive Scsi 10", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuScsiDisk{}, + Passthrough: &QemuScsiPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + // Invalid Disks Mutually exclusive VirtIO + {name: "Invalid Disks MutuallyExclusive VirtIO 0", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 1", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuVirtIODisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 2", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 3", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuVirtIODisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 4", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{ + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 5", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{ + Disk: &QemuVirtIODisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 6", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuVirtIODisk{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 7", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{ + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuVirtIODisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 8", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + Disk: &QemuVirtIODisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 9", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + {name: "Invalid Disks MutuallyExclusive VirtIO 10", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{ + CdRom: &QemuCdRom{}, + CloudInit: &QemuCloudInitDisk{}, + Disk: &QemuVirtIODisk{}, + Passthrough: &QemuVirtIOPassthrough{}, + }}}}, + err: errors.New(Error_QemuDisk_MutuallyExclusive), + }, + // Invalid Disks CdRom Ide + {name: "Invalid Disks CdRom Ide errors.New(Error_IsoFile_File) 0", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Ide errors.New(Error_IsoFile_File) 1", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{Storage: "test"}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Ide errors.New(Error_IsoFile_Storage)", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test"}}}}}}, + err: errors.New(Error_IsoFile_Storage), + }, + {name: "Invalid Disks CdRom Ide errors.New(Error_QemuCdRom_MutuallyExclusive)", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}, Passthrough: true}}}}}, + err: errors.New(Error_QemuCdRom_MutuallyExclusive), + }, + // Invalid Disks CdRom Sata + {name: "Invalid Disks CdRom Sata errors.New(Error_IsoFile_File) 0", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Sata errors.New(Error_IsoFile_File) 1", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{Storage: "test"}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Sata errors.New(Error_IsoFile_Storage)", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test"}}}}}}, + err: errors.New(Error_IsoFile_Storage), + }, + {name: "Invalid Disks CdRom Sata errors.New(Error_QemuCdRom_MutuallyExclusive)", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}, Passthrough: true}}}}}, + err: errors.New(Error_QemuCdRom_MutuallyExclusive), + }, + // Invalid Disks CdRom Scsi + {name: "Invalid Disks CdRom Scsi errors.New(Error_IsoFile_File) 0", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Scsi errors.New(Error_IsoFile_File) 1", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{Storage: "test"}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom Scsi errors.New(Error_IsoFile_Storage)", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test"}}}}}}, + err: errors.New(Error_IsoFile_Storage), + }, + {name: "Invalid Disks CdRom Scsi errors.New(Error_QemuCdRom_MutuallyExclusive)", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}, Passthrough: true}}}}}, + err: errors.New(Error_QemuCdRom_MutuallyExclusive), + }, + // Invalid Disks CdRom VirtIO + {name: "Invalid Disks CdRom VirtIO errors.New(Error_IsoFile_File) 0", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom VirtIO errors.New(Error_IsoFile_File) 1", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{Storage: "test"}}}}}}, + err: errors.New(Error_IsoFile_File), + }, + {name: "Invalid Disks CdRom VirtIO errors.New(Error_IsoFile_Storage)", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test"}}}}}}, + err: errors.New(Error_IsoFile_Storage), + }, + {name: "Invalid Disks CdRom VirtIO errors.New(Error_QemuCdRom_MutuallyExclusive)", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}, Passthrough: true}}}}}, + err: errors.New(Error_QemuCdRom_MutuallyExclusive), + }, + // Invalid Disks CloudInit Ide + {name: `Invalid Disks CloudInit Ide QemuDiskFormat("").Error() 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Ide QemuDiskFormat("").Error() 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Storage: "test"}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Ide errors.New(Error_QemuCloudInitDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw}}}}}, + err: errors.New(Error_QemuCloudInitDisk_Storage), + }, + // Invalid Disks CloudInit Sata + {name: `Invalid Disks CloudInit Sata QemuDiskFormat("").Error() 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Sata QemuDiskFormat("").Error() 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Storage: "test"}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Sata errors.New(Error_QemuCloudInitDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw}}}}}, + err: errors.New(Error_QemuCloudInitDisk_Storage), + }, + // Invalid Disks CloudInit Scsi + {name: `Invalid Disks CloudInit Scsi QemuDiskFormat("").Error() 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Scsi QemuDiskFormat("").Error() 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Storage: "test"}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit Scsi errors.New(Error_QemuCloudInitDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw}}}}}, + err: errors.New(Error_QemuCloudInitDisk_Storage), + }, + // Invalid Disks CloudInit VirtIO + {name: `Invalid Disks CloudInit VirtIO QemuDiskFormat("").Error() 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit VirtIO QemuDiskFormat("").Error() 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Storage: "test"}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks CloudInit VirtIO errors.New(Error_QemuCloudInitDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw}}}}}, + err: errors.New(Error_QemuCloudInitDisk_Storage), + }, + // Invalid Disks Disk Ide + {name: `Invalid Disks Disk Ide QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Ide QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Ide QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Disk Ide QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: ""}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Serial: "!@^$^&$^&"}, + }}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal()), + }}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDisk_Size)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Size: 0, + }}}}}, + err: errors.New(Error_QemuDisk_Size), + }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "", + }}}}}, + err: errors.New(Error_QemuDisk_Storage), + }, + // Invalid Disks Disk Sata + {name: `Invalid Disks Disk Sata QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Sata QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Sata QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Disk Sata QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Format: ""}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Serial: "!@^$^&$^&"}, + }}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal()), + }}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDisk_Size)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Size: 0, + }}}}}, + err: errors.New(Error_QemuDisk_Size), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "", + }}}}}, + err: errors.New(Error_QemuDisk_Storage), + }, + // Invalid Disks Disk Scsi + {name: `Invalid Disks Disk Scsi QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Scsi QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk Scsi QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Disk Scsi QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: ""}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Serial: "!@^$^&$^&"}, + }}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal()), + }}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDisk_Size)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Size: 0, + }}}}}, + err: errors.New(Error_QemuDisk_Size), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "", + }}}}}, + err: errors.New(Error_QemuDisk_Storage), + }, + // Invalid Disks Disk VirtIO + {name: `Invalid Disks Disk VirtIO QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk VirtIO QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Disk VirtIO QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Disk VirtIO QemuDiskFormat("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: ""}}}}}, + err: QemuDiskFormat("").Error(), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Serial: "!@^$^&$^&"}, + }}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal()), + }}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDisk_Size)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Size: 0, + }}}}}, + err: errors.New(Error_QemuDisk_Size), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDisk_Storage)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "", + }}}}}, + err: errors.New(Error_QemuDisk_Storage), + }, + // Invalid Disks Passthrough Ide + {name: `Invalid Disks Passthrough Ide QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Ide QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDisk_File)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: ""}}}}}, + err: errors.New(Error_QemuDisk_File), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: "/dev/disk/by-id/scsi1", Serial: "!@^$^&$^&"}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + // Invalid Disks Passthrough Sata + {name: `Invalid Disks Passthrough Sata QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Sata QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDisk_File)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: ""}}}}}, + err: errors.New(Error_QemuDisk_File), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: "/dev/disk/by-id/scsi1", Serial: "!@^$^&$^&"}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + // Invalid Disks Passthrough Scsi + {name: `Invalid Disks Passthrough Scsi QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough Scsi QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDisk_File)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: ""}}}}}, + err: errors.New(Error_QemuDisk_File), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: "/dev/disk/by-id/scsi1", Serial: "!@^$^&$^&"}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + // Invalid Disks Passthrough VirtIO + {name: `Invalid Disks Passthrough VirtIO QemuDiskAsyncIO("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: "invalid"}}}}}, + err: QemuDiskAsyncIO("").Error(), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + }, + {name: `Invalid Disks Passthrough VirtIO QemuDiskCache("").Error()`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Cache: "invalid"}}}}}, + err: QemuDiskCache("").Error(), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDisk_File)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: ""}}}}}, + err: errors.New(Error_QemuDisk_File), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskSerial_IllegalCharacter)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: "/dev/disk/by-id/scsi1", Serial: "!@^$^&$^&"}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalCharacter), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskSerial_IllegalLength)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, + err: errors.New(Error_QemuDiskSerial_IllegalLength), + }, + } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + // Test the encoding logic to encode the ssh keys func Test_sshKeyUrlEncode(t *testing.T) { input := test_sshKeyUrlEncode_Input() From 1fe52d4e55ab1cfcc8140143483926867829c1fc Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:45:46 +0000 Subject: [PATCH 079/191] refactor: update json keys --- proxmox/config_qemu_disk.go | 28 ++++++++--------- proxmox/config_qemu_disk_ide.go | 34 ++++++++++---------- proxmox/config_qemu_disk_sata.go | 42 ++++++++++++------------- proxmox/config_qemu_disk_scsi.go | 50 +++++++++++++++--------------- proxmox/config_qemu_disk_virtio.go | 44 +++++++++++++------------- 5 files changed, 99 insertions(+), 99 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 536d7f6e..76edd333 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -439,8 +439,8 @@ func (asyncIO QemuDiskAsyncIO) Validate() error { } type QemuDiskBandwidth struct { - Data QemuDiskBandwidthData - Iops QemuDiskBandwidthIops + Data QemuDiskBandwidthData `json:"data,omitempty"` + Iops QemuDiskBandwidthIops `json:"iops,omitempty"` } func (bandwidth QemuDiskBandwidth) Validate() error { @@ -452,8 +452,8 @@ func (bandwidth QemuDiskBandwidth) Validate() error { } type QemuDiskBandwidthData struct { - ReadLimit QemuDiskBandwidthDataLimit - WriteLimit QemuDiskBandwidthDataLimit + ReadLimit QemuDiskBandwidthDataLimit `json:"read,omitempty"` + WriteLimit QemuDiskBandwidthDataLimit `json:"write,omitempty"` } func (data QemuDiskBandwidthData) Validate() error { @@ -465,8 +465,8 @@ func (data QemuDiskBandwidthData) Validate() error { } type QemuDiskBandwidthDataLimit struct { - Burst float32 // 0 = default - Concurrent float32 // 0 = unlimited + Burst float32 `json:"burst,omitempty"` // 0 = default + Concurrent float32 `json:"concurrent,omitempty"` // 0 = unlimited } const ( @@ -485,8 +485,8 @@ func (limit QemuDiskBandwidthDataLimit) Validate() error { } type QemuDiskBandwidthIops struct { - ReadLimit QemuDiskBandwidthIopsLimit - WriteLimit QemuDiskBandwidthIopsLimit + ReadLimit QemuDiskBandwidthIopsLimit `json:"read,omitempty"` + WriteLimit QemuDiskBandwidthIopsLimit `json:"write,omitempty"` } func (iops QemuDiskBandwidthIops) Validate() error { @@ -498,8 +498,8 @@ func (iops QemuDiskBandwidthIops) Validate() error { } type QemuDiskBandwidthIopsLimit struct { - Burst uint // 0 = default - Concurrent uint // 0 = unlimited + Burst uint `json:"burst,omitempty"` // 0 = default + Concurrent uint `json:"concurrent,omitempty"` // 0 = unlimited } const ( @@ -609,10 +609,10 @@ const ( ) type qemuStorage struct { - CdRom *QemuCdRom `json:"cdrom,omitempty"` - CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` - Disk *qemuDisk `json:"disk,omitempty"` - Passthrough *qemuDisk `json:"passthrough,omitempty"` + CdRom *QemuCdRom + CloudInit *QemuCloudInitDisk + Disk *qemuDisk + Passthrough *qemuDisk } func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 69c801be..62363a1a 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -4,17 +4,17 @@ import "strconv" type QemuIdeDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup,omitempty"` + Backup bool `json:"backup"` Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard,omitempty"` - EmulateSSD bool `json:"emulatessd,omitempty"` - Format QemuDiskFormat `json:"format,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` Id *uint `json:"id,omitempty"` - Replicate bool `json:"replicate,omitempty"` + Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size,omitempty"` - Storage string `json:"storage,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { @@ -109,16 +109,16 @@ func (disks QemuIdeDisks) Validate() error { } type QemuIdePassthrough struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - File string - Replicate bool - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect } func (passthrough *QemuIdePassthrough) convertDataStructure() *qemuDisk { diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 69759d8e..340c663a 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -4,17 +4,17 @@ import "strconv" type QemuSataDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup,omitempty"` + Backup bool `json:"backup"` Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard,omitempty"` - EmulateSSD bool `json:"emulatessd,omitempty"` - Format QemuDiskFormat `json:"format,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` Id *uint `json:"id,omitempty"` - Replicate bool `json:"replicate,omitempty"` + Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size,omitempty"` - Storage string `json:"storage,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { @@ -121,16 +121,16 @@ func (disks QemuSataDisks) Validate() error { } type QemuSataPassthrough struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - File string - Replicate bool - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect } func (passthrough *QemuSataPassthrough) convertDataStructure() *qemuDisk { @@ -153,10 +153,10 @@ func (passthrough QemuSataPassthrough) Validate() error { } type QemuSataStorage struct { - CdRom *QemuCdRom - CloudInit *QemuCloudInitDisk - Disk *QemuSataDisk - Passthrough *QemuSataPassthrough + CdRom *QemuCdRom `json:"cdrom,omitempty"` + CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` + Disk *QemuSataDisk `json:"disk,omitempty"` + Passthrough *QemuSataPassthrough `json:"passthrough,omitempty"` } // TODO write test diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 851dc1e6..7a304a1f 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -4,19 +4,19 @@ import "strconv" type QemuScsiDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup,omitempty"` + Backup bool `json:"backup"` Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard,omitempty"` - EmulateSSD bool `json:"emulatessd,omitempty"` - Format QemuDiskFormat `json:"format,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` Id *uint `json:"id,omitempty"` - IOThread bool `json:"iothread,omitempty"` - ReadOnly bool `json:"readonly,omitempty"` - Replicate bool `json:"replicate,omitempty"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size,omitempty"` - Storage string `json:"storage,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { @@ -275,18 +275,18 @@ func (disks QemuScsiDisks) Validate() error { } type QemuScsiPassthrough struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - EmulateSSD bool - File string - IOThread bool - ReadOnly bool - Replicate bool - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect } func (passthrough *QemuScsiPassthrough) convertDataStructure() *qemuDisk { @@ -311,10 +311,10 @@ func (passthrough QemuScsiPassthrough) Validate() error { } type QemuScsiStorage struct { - CdRom *QemuCdRom - CloudInit *QemuCloudInitDisk - Disk *QemuScsiDisk - Passthrough *QemuScsiPassthrough + CdRom *QemuCdRom `json:"cdrom,omitempty"` + CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` + Disk *QemuScsiDisk `json:"disk,omitempty"` + Passthrough *QemuScsiPassthrough `json:"passthrough,omitempty"` } // TODO write test diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index a16ab105..fd181109 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -4,18 +4,18 @@ import "strconv" type QemuVirtIODisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup,omitempty"` + Backup bool `json:"backup"` Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard,omitempty"` - Format QemuDiskFormat `json:"format,omitempty"` + Discard bool `json:"discard"` + Format QemuDiskFormat `json:"format"` Id *uint `json:"id,omitempty"` - IOThread bool `json:"iothread,omitempty"` - ReadOnly bool `json:"readonly,omitempty"` - Replicate bool `json:"replicate,omitempty"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size,omitempty"` - Storage string `json:"storage,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { @@ -183,16 +183,16 @@ func (disks QemuVirtIODisks) Validate() error { } type QemuVirtIOPassthrough struct { - AsyncIO QemuDiskAsyncIO - Backup bool - Bandwidth QemuDiskBandwidth - Cache QemuDiskCache - Discard bool - File string - IOThread bool - ReadOnly bool - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + File string `json:"file"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect } func (passthrough *QemuVirtIOPassthrough) convertDataStructure() *qemuDisk { @@ -215,10 +215,10 @@ func (passthrough QemuVirtIOPassthrough) Validate() error { } type QemuVirtIOStorage struct { - CdRom *QemuCdRom - CloudInit *QemuCloudInitDisk - Disk *QemuVirtIODisk - Passthrough *QemuVirtIOPassthrough + CdRom *QemuCdRom `json:"cdrom,omitempty"` + CloudInit *QemuCloudInitDisk `json:"cloudinit,omitempty"` + Disk *QemuVirtIODisk `json:"disk,omitempty"` + Passthrough *QemuVirtIOPassthrough `json:"passthrough,omitempty"` } // TODO write test From 3bf288862f0bbfa76beb1a8acacc0b029c90e96d Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:33:32 +0000 Subject: [PATCH 080/191] fix: not checking for duplicate cloudinit disk --- proxmox/config_qemu_disk.go | 35 ++++++++++++++-- proxmox/config_qemu_disk_ide.go | 24 +++++++++-- proxmox/config_qemu_disk_sata.go | 26 +++++++++--- proxmox/config_qemu_disk_scsi.go | 26 +++++++++--- proxmox/config_qemu_disk_virtio.go | 24 +++++++++-- proxmox/config_qemu_test.go | 65 ++++++++++++++++++++++++++---- 6 files changed, 171 insertions(+), 29 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 76edd333..48427dc0 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -145,8 +145,16 @@ type QemuCloudInitDisk struct { const ( Error_QemuCloudInitDisk_Storage string = "storage should not be empty" + Error_QemuCloudInitDisk_OnlyOne string = "only one cloud init disk may exist" ) +func (QemuCloudInitDisk) checkDuplicates(numberOFCloudInitDrives uint8) error { + if numberOFCloudInitDrives > 1 { + return errors.New(Error_QemuCloudInitDisk_OnlyOne) + } + return nil +} + // TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { return cloudInit.Storage + ":cloudinit,format=" + string(cloudInit.Format) @@ -745,26 +753,45 @@ func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID } func (storages QemuStorages) Validate() (err error) { + var numberOfCloudInitDevices uint8 + var CloudInit uint8 if storages.Ide != nil { - err = storages.Ide.Validate() + CloudInit, err = storages.Ide.validate() if err != nil { return } + numberOfCloudInitDevices += CloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return + } } if storages.Sata != nil { - err = storages.Sata.Validate() + CloudInit, err = storages.Sata.validate() if err != nil { return } + numberOfCloudInitDevices += CloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return + } } if storages.Scsi != nil { - err = storages.Scsi.Validate() + CloudInit, err = storages.Scsi.validate() if err != nil { return } + numberOfCloudInitDevices += CloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return + } } if storages.VirtIO != nil { - err = storages.VirtIO.Validate() + CloudInit, err = storages.VirtIO.validate() + if err != nil { + return + } + numberOfCloudInitDevices += CloudInit + err = QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices) } return } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 62363a1a..5b0491db 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -95,17 +95,27 @@ func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { return nil } -func (disks QemuIdeDisks) Validate() error { +func (disks QemuIdeDisks) Validate() (err error) { + _, err = disks.validate() + return +} + +func (disks QemuIdeDisks) validate() (numberOfCloudInitDevices uint8, err error) { diskMap := disks.mapToIntMap() + var cloudInit uint8 for _, e := range diskMap { if e != nil { - err := e.Validate() + cloudInit, err = e.validate() if err != nil { - return err + return + } + numberOfCloudInitDevices += cloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return } } } - return nil + return } type QemuIdePassthrough struct { @@ -213,6 +223,11 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { } func (storage QemuIdeStorage) Validate() (err error) { + _, err = storage.validate() + return +} + +func (storage QemuIdeStorage) validate() (CloudInit uint8, err error) { // First check if more than one item is nil var subTypeSet bool if storage.CdRom != nil { @@ -223,6 +238,7 @@ func (storage QemuIdeStorage) Validate() (err error) { return } subTypeSet = true + CloudInit = 1 } if storage.Disk != nil { if err = diskSubtypeSet(subTypeSet); err != nil { diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 340c663a..2dcd0732 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -107,17 +107,27 @@ func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { return nil } -func (disks QemuSataDisks) Validate() error { +func (disks QemuSataDisks) Validate() (err error) { + _, err = disks.validate() + return +} + +func (disks QemuSataDisks) validate() (numberOfCloudInitDevices uint8, err error) { diskMap := disks.mapToIntMap() + var cloudInit uint8 for _, e := range diskMap { if e != nil { - err := e.Validate() + cloudInit, err = e.validate() if err != nil { - return err + return + } + numberOfCloudInitDevices += cloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return } } } - return nil + return } type QemuSataPassthrough struct { @@ -224,7 +234,12 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { }} } -func (storage *QemuSataStorage) Validate() (err error) { +func (storage QemuSataStorage) Validate() (err error) { + _, err = storage.validate() + return +} + +func (storage QemuSataStorage) validate() (CloudInit uint8, err error) { // First check if more than one item is nil var subTypeSet bool if storage.CdRom != nil { @@ -235,6 +250,7 @@ func (storage *QemuSataStorage) Validate() (err error) { return } subTypeSet = true + CloudInit = 1 } if storage.Disk != nil { if err = diskSubtypeSet(subTypeSet); err != nil { diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 7a304a1f..6cb5c12d 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -261,17 +261,27 @@ func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { return nil } -func (disks QemuScsiDisks) Validate() error { +func (disks QemuScsiDisks) Validate() (err error) { + _, err = disks.validate() + return +} + +func (disks QemuScsiDisks) validate() (numberOfCloudInitDevices uint8, err error) { diskMap := disks.mapToIntMap() + var cloudInit uint8 for _, e := range diskMap { if e != nil { - err := e.Validate() + cloudInit, err = e.validate() if err != nil { - return err + return + } + numberOfCloudInitDevices += cloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return } } } - return nil + return } type QemuScsiPassthrough struct { @@ -386,7 +396,12 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { }} } -func (storage *QemuScsiStorage) Validate() (err error) { +func (storage QemuScsiStorage) Validate() (err error) { + _, err = storage.validate() + return +} + +func (storage QemuScsiStorage) validate() (CloudInit uint8, err error) { // First check if more than one item is nil var subTypeSet bool if storage.CdRom != nil { @@ -397,6 +412,7 @@ func (storage *QemuScsiStorage) Validate() (err error) { return } subTypeSet = true + CloudInit = 1 } if storage.Disk != nil { if err = diskSubtypeSet(subTypeSet); err != nil { diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index fd181109..8641ed87 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -169,17 +169,27 @@ func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODis return nil } -func (disks QemuVirtIODisks) Validate() error { +func (disks QemuVirtIODisks) Validate() (err error) { + _, err = disks.validate() + return +} + +func (disks QemuVirtIODisks) validate() (numberOfCloudInitDevices uint8, err error) { diskMap := disks.mapToIntMap() + var cloudInit uint8 for _, e := range diskMap { if e != nil { - err := e.Validate() + cloudInit, err = e.validate() if err != nil { - return err + return + } + numberOfCloudInitDevices += cloudInit + if err = (QemuCloudInitDisk{}.checkDuplicates(numberOfCloudInitDevices)); err != nil { + return } } } - return nil + return } type QemuVirtIOPassthrough struct { @@ -288,6 +298,11 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { } func (storage QemuVirtIOStorage) Validate() (err error) { + _, err = storage.validate() + return +} + +func (storage QemuVirtIOStorage) validate() (CloudInit uint8, err error) { // First check if more than one item is nil var subTypeSet bool if storage.CdRom != nil { @@ -298,6 +313,7 @@ func (storage QemuVirtIOStorage) Validate() (err error) { return } subTypeSet = true + CloudInit = 1 } if storage.Disk != nil { if err = diskSubtypeSet(subTypeSet); err != nil { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index ad8bfd0f..68a10e68 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -98,6 +98,7 @@ func Test_ConfigQemu_Validate(t *testing.T) { }, }, } + validCloudInit := QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"} testData := []struct { name string input ConfigQemu @@ -126,13 +127,17 @@ func Test_ConfigQemu_Validate(t *testing.T) { }}, }, // Valid Disks CloudInit - {name: "Valid Disks CloudInit", - input: ConfigQemu{Disks: &QemuStorages{ - Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, - Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, - Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, - VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "Test"}}}, - }}, + {name: "Valid Disks CloudInit Ide", + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &validCloudInit}}}}, + }, + {name: "Valid Disks CloudInit Sata", + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &validCloudInit}}}}, + }, + {name: "Valid Disks CloudInit Scsi", + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &validCloudInit}}}}, + }, + {name: "Valid Disks CloudInit VirtIO", + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &validCloudInit}}}}, }, // Valid Disks Disk {name: "Valid Disks Disk", @@ -605,6 +610,52 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test", Storage: "test"}, Passthrough: true}}}}}, err: errors.New(Error_QemuCdRom_MutuallyExclusive), }, + // Invalid Disks CloudInit Duplicate + {name: "Invalid Disks CloudInit Duplicate errors.New(Error_QemuCloudInitDisk_OnlyOne)", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &validCloudInit}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &validCloudInit}}, + Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &validCloudInit}}, + VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &validCloudInit}}, + }}, + err: errors.New(Error_QemuCloudInitDisk_OnlyOne), + }, + {name: "Invalid Disks CloudInit Duplicate Ide errors.New(Error_QemuCloudInitDisk_OnlyOne)", + input: ConfigQemu{Disks: &QemuStorages{ + Ide: &QemuIdeDisks{ + Disk_0: &QemuIdeStorage{CloudInit: &validCloudInit}, + Disk_1: &QemuIdeStorage{CloudInit: &validCloudInit}, + }, + }}, + err: errors.New(Error_QemuCloudInitDisk_OnlyOne), + }, + {name: "Invalid Disks CloudInit Duplicate Sata errors.New(Error_QemuCloudInitDisk_OnlyOne)", + input: ConfigQemu{Disks: &QemuStorages{ + Sata: &QemuSataDisks{ + Disk_0: &QemuSataStorage{CloudInit: &validCloudInit}, + Disk_1: &QemuSataStorage{CloudInit: &validCloudInit}, + }, + }}, + err: errors.New(Error_QemuCloudInitDisk_OnlyOne), + }, + {name: "Invalid Disks CloudInit Duplicate Scsi errors.New(Error_QemuCloudInitDisk_OnlyOne)", + input: ConfigQemu{Disks: &QemuStorages{ + Scsi: &QemuScsiDisks{ + Disk_0: &QemuScsiStorage{CloudInit: &validCloudInit}, + Disk_1: &QemuScsiStorage{CloudInit: &validCloudInit}, + }, + }}, + err: errors.New(Error_QemuCloudInitDisk_OnlyOne), + }, + {name: "Invalid Disks CloudInit Duplicate VirtIO errors.New(Error_QemuCloudInitDisk_OnlyOne)", + input: ConfigQemu{Disks: &QemuStorages{ + VirtIO: &QemuVirtIODisks{ + Disk_0: &QemuVirtIOStorage{CloudInit: &validCloudInit}, + Disk_1: &QemuVirtIOStorage{CloudInit: &validCloudInit}, + }, + }}, + err: errors.New(Error_QemuCloudInitDisk_OnlyOne), + }, // Invalid Disks CloudInit Ide {name: `Invalid Disks CloudInit Ide QemuDiskFormat("").Error() 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{}}}}}, From 651d6457f5fe068476dc0e2539c94eadec741a80 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:39:06 +0000 Subject: [PATCH 081/191] Add TODO --- proxmox/config_qemu.go | 1 + 1 file changed, 1 insertion(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 9ce0041f..526e45b0 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -691,6 +691,7 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef func (config ConfigQemu) Validate() (err error) { // TODO test all other use cases + // TODO has no context about changes caused by updating the vm if config.Disks != nil { err = config.Disks.Validate() if err != nil { From 199a7d1f6e7cb5c5b2b1e8431d5ac6112ac0fcbd Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:08:14 +0000 Subject: [PATCH 082/191] refactor: move defaults to seperate fuction moved the defaults to its own function, to make testing easier --- proxmox/config_qemu.go | 60 ++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 526e45b0..10e98bd8 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -115,6 +115,42 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { return } +func (config *ConfigQemu) defaults() { + if config.Boot == "" { + config.Boot = "cdn" + } + if config.Bios == "" { + config.Bios = "seabios" + } + if config.Onboot == nil { + config.Onboot = PointerBool(true) + } + if config.Hotplug == "" { + config.Hotplug = "network,disk,usb" + } + if config.QemuCores == 0 { + config.QemuCores = 1 + } + if config.QemuCpu == "" { + config.QemuCpu = "host" + } + if config.QemuKVM == nil { + config.QemuKVM = PointerBool(true) + } + if config.QemuOs == "" { + config.QemuOs = "other" + } + if config.QemuSockets == 0 { + config.QemuSockets = 1 + } + if config.Scsihw == "" { + config.Scsihw = "lsi" + } + if config.Tablet == nil { + config.Tablet = PointerBool(true) + } +} + func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { var itemsToDelete string @@ -318,16 +354,12 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu //boot by default from hard disk (c), CD-ROM (d), network (n). if _, isSet := params["boot"]; isSet { config.Boot = params["boot"].(string) - } else { - config.Boot = "cdn" } if _, isSet := params["bootdisk"]; isSet { config.BootDisk = params["bootdisk"].(string) } if _, isSet := params["bios"]; isSet { config.Bios = params["bios"].(string) - } else { - config.Bios = "seabios" } if _, isSet := params["cicustom"]; isSet { config.CIcustom = params["cicustom"].(string) @@ -344,8 +376,6 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu //Can be network,disk,cpu,memory,usb if _, isSet := params["hotplug"]; isSet { config.Hotplug = params["hotplug"].(string) - } else { - config.Hotplug = "network,disk,usb" } if _, isSet := params["hookscript"]; isSet { config.Hookscript = params["hookscript"].(string) @@ -361,36 +391,24 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu } if _, isSet := params["onboot"]; isSet { config.Onboot = PointerBool(Itob(int(params["onboot"].(float64)))) - } else { - config.Onboot = PointerBool(true) } if _, isSet := params["cores"]; isSet { config.QemuCores = int(params["cores"].(float64)) - } else { - config.QemuCores = 1 } if _, isSet := params["cpu"]; isSet { config.QemuCpu = params["cpu"].(string) - } else { - config.QemuCpu = "host" } if _, isSet := params["kvm"]; isSet { config.QemuKVM = PointerBool(Itob(int(params["kvm"].(float64)))) - } else { - config.QemuKVM = PointerBool(true) } if _, isSet := params["numa"]; isSet { config.QemuNuma = PointerBool(Itob(int(params["numa"].(float64)))) } if _, isSet := params["ostype"]; isSet { config.QemuOs = params["ostype"].(string) - } else { - config.QemuOs = "other" } if _, isSet := params["sockets"]; isSet { config.QemuSockets = int(params["sockets"].(float64)) - } else { - config.QemuSockets = 1 } if _, isSet := params["vcpus"]; isSet { vCpu := int(params["vcpus"].(float64)) @@ -400,8 +418,6 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu } if _, isSet := params["scsihw"]; isSet { config.Scsihw = params["scsihw"].(string) - } else { - config.Scsihw = "lsi" } if _, isSet := params["searchdomain"]; isSet { config.Searchdomain = params["searchdomain"].(string) @@ -414,8 +430,6 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu } if _, isSet := params["tablet"]; isSet { config.Tablet = PointerBool(Itob(int(params["tablet"].(float64)))) - } else { - config.Tablet = PointerBool(true) } if _, isSet := params["tags"]; isSet { config.Tags = strings.TrimSpace(params["tags"].(string)) @@ -987,7 +1001,7 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e if err != nil { return } - + config.defaults() // HAstate is return by the api for a vm resource type but not the HAgroup err = client.ReadVMHA(vmr) if err == nil { From f42049a8c886a2c816fd95c58dfc925f9023ea5e Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:35:36 +0000 Subject: [PATCH 083/191] refactor: move defaults to seperate fuction moved more defaults to its own function, to make testing easier --- proxmox/config_qemu.go | 99 +++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 10e98bd8..b9644154 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -116,39 +116,70 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { } func (config *ConfigQemu) defaults() { + if config == nil { + return + } if config.Boot == "" { config.Boot = "cdn" } if config.Bios == "" { config.Bios = "seabios" } + if config.EFIDisk == nil { + config.EFIDisk = QemuDevice{} + } if config.Onboot == nil { config.Onboot = PointerBool(true) } if config.Hotplug == "" { config.Hotplug = "network,disk,usb" } + if config.Ipconfig == nil { + config.Ipconfig = IpconfigMap{} + } if config.QemuCores == 0 { config.QemuCores = 1 } if config.QemuCpu == "" { config.QemuCpu = "host" } + if config.QemuDisks == nil { + config.QemuDisks = QemuDevices{} + } if config.QemuKVM == nil { config.QemuKVM = PointerBool(true) } + if config.QemuNetworks == nil { + config.QemuNetworks = QemuDevices{} + } if config.QemuOs == "" { config.QemuOs = "other" } + if config.QemuPCIDevices == nil { + config.QemuPCIDevices = QemuDevices{} + } + if config.QemuSerials == nil { + config.QemuSerials = QemuDevices{} + } if config.QemuSockets == 0 { config.QemuSockets = 1 } + if config.QemuUnusedDisks == nil { + config.QemuUnusedDisks = QemuDevices{} + } + if config.QemuUsbs == nil { + config.QemuUsbs = QemuDevices{} + } + if config.QemuVga == nil { + config.QemuVga = QemuDevice{} + } if config.Scsihw == "" { config.Scsihw = "lsi" } if config.Tablet == nil { config.Tablet = PointerBool(true) } + } func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { @@ -321,17 +352,7 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu // description:Base image // cores:2 ostype:l26 - config = &ConfigQemu{ - EFIDisk: QemuDevice{}, - QemuDisks: QemuDevices{}, - QemuUnusedDisks: QemuDevices{}, - QemuVga: QemuDevice{}, - QemuNetworks: QemuDevices{}, - QemuSerials: QemuDevices{}, - QemuPCIDevices: QemuDevices{}, - QemuUsbs: QemuDevices{}, - Ipconfig: IpconfigMap{}, - } + config = &ConfigQemu{} if _, isSet := params["agent"]; isSet { switch params["agent"].(type) { @@ -443,11 +464,14 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu } } - for _, ipconfigName := range ipconfigNames { - ipConfStr := params[ipconfigName] - id := rxDeviceID.FindStringSubmatch(ipconfigName) - ipconfigID, _ := strconv.Atoi(id[0]) - config.Ipconfig[ipconfigID] = ipConfStr + if len(ipconfigNames) > 0 { + config.Ipconfig = IpconfigMap{} + for _, ipconfigName := range ipconfigNames { + ipConfStr := params[ipconfigName] + id := rxDeviceID.FindStringSubmatch(ipconfigName) + ipconfigID, _ := strconv.Atoi(id[0]) + config.Ipconfig[ipconfigID] = ipConfStr + } } config.Disks = QemuStorages{}.mapToStruct(params) @@ -469,29 +493,34 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu // log.Printf("[DEBUG] unusedDiskNames: %v", unusedDiskNames) // } - for _, unusedDiskName := range unusedDiskNames { - unusedDiskConfStr := params[unusedDiskName].(string) - finalDiskConfMap := QemuDevice{} + if len(unusedDiskNames) > 0 { + config.QemuUnusedDisks = QemuDevices{} + for _, unusedDiskName := range unusedDiskNames { + unusedDiskConfStr := params[unusedDiskName].(string) + finalDiskConfMap := QemuDevice{} - // parse "unused0" to get the id '0' as an int - id := rxDeviceID.FindStringSubmatch(unusedDiskName) - diskID, err := strconv.Atoi(id[0]) - if err != nil { - return nil, fmt.Errorf(fmt.Sprintf("Unable to parse unused disk id from input string '%v' tried to convert '%v' to integer.", unusedDiskName, diskID)) + // parse "unused0" to get the id '0' as an int + id := rxDeviceID.FindStringSubmatch(unusedDiskName) + diskID, err := strconv.Atoi(id[0]) + if err != nil { + return nil, fmt.Errorf(fmt.Sprintf("Unable to parse unused disk id from input string '%v' tried to convert '%v' to integer.", unusedDiskName, diskID)) + } + finalDiskConfMap["slot"] = diskID + + // parse the attributes from the unused disk + // extract the storage and file path from the unused disk entry + parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") + storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") + finalDiskConfMap["storage"] = storageName + finalDiskConfMap["file"] = fileName + + config.QemuUnusedDisks[diskID] = finalDiskConfMap + config.QemuUnusedDisks[diskID] = finalDiskConfMap + config.QemuUnusedDisks[diskID] = finalDiskConfMap } - finalDiskConfMap["slot"] = diskID - - // parse the attributes from the unused disk - // extract the storage and file path from the unused disk entry - parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") - storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") - finalDiskConfMap["storage"] = storageName - finalDiskConfMap["file"] = fileName - - config.QemuUnusedDisks[diskID] = finalDiskConfMap } - //Display + if vga, isSet := params["vga"]; isSet { vgaList := strings.Split(vga.(string), ",") vgaMap := QemuDevice{} From c1438e2a7d438ad9aeb68aca835b3e31e1785487 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:39:37 +0000 Subject: [PATCH 084/191] refactor: remove pointer inside func --- proxmox/config_qemu.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index b9644154..eedea685 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -342,7 +342,7 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[st return } -func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu, err error) { +func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error) { // vmConfig Sample: map[ cpu:host // net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0 // ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048 @@ -352,7 +352,7 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu // description:Base image // cores:2 ostype:l26 - config = &ConfigQemu{} + config := ConfigQemu{} if _, isSet := params["agent"]; isSet { switch params["agent"].(type) { @@ -656,8 +656,7 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (config *ConfigQemu } } - return - + return &config, nil } func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { From 221764a8ca8bc37549b0c6ec8b5891a70cc46c85 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 11:01:47 +0000 Subject: [PATCH 085/191] fix: item not initialized before use --- proxmox/config_qemu.go | 154 ++++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 71 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index eedea685..7bc9f87b 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -540,39 +540,42 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } - for _, nicName := range nicNames { - nicConfStr := params[nicName] - nicConfList := strings.Split(nicConfStr.(string), ",") - - id := rxDeviceID.FindStringSubmatch(nicName) - nicID, _ := strconv.Atoi(id[0]) - model, macaddr := ParseSubConf(nicConfList[0], "=") - - // Add model and MAC address. - nicConfMap := QemuDevice{ - "id": nicID, - "model": model, - "macaddr": macaddr, - } + if len(nicNames) > 0 { + config.QemuNetworks = QemuDevices{} + for _, nicName := range nicNames { + nicConfStr := params[nicName] + nicConfList := strings.Split(nicConfStr.(string), ",") + + id := rxDeviceID.FindStringSubmatch(nicName) + nicID, _ := strconv.Atoi(id[0]) + model, macaddr := ParseSubConf(nicConfList[0], "=") + + // Add model and MAC address. + nicConfMap := QemuDevice{ + "id": nicID, + "model": model, + "macaddr": macaddr, + } - // Add rest of device config. - nicConfMap.readDeviceConfig(nicConfList[1:]) - switch nicConfMap["firewall"] { - case 1: - nicConfMap["firewall"] = true - case 0: - nicConfMap["firewall"] = false - } - switch nicConfMap["link_down"] { - case 1: - nicConfMap["link_down"] = true - case 0: - nicConfMap["link_down"] = false - } + // Add rest of device config. + nicConfMap.readDeviceConfig(nicConfList[1:]) + switch nicConfMap["firewall"] { + case 1: + nicConfMap["firewall"] = true + case 0: + nicConfMap["firewall"] = false + } + switch nicConfMap["link_down"] { + case 1: + nicConfMap["link_down"] = true + case 0: + nicConfMap["link_down"] = false + } - // And device config to networks. - if len(nicConfMap) > 0 { - config.QemuNetworks[nicID] = nicConfMap + // And device config to networks. + if len(nicConfMap) > 0 { + config.QemuNetworks[nicID] = nicConfMap + } } } @@ -585,18 +588,21 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } - for _, serialName := range serialNames { - id := rxDeviceID.FindStringSubmatch(serialName) - serialID, _ := strconv.Atoi(id[0]) + if len(serialNames) > 0 { + config.QemuSerials = QemuDevices{} + for _, serialName := range serialNames { + id := rxDeviceID.FindStringSubmatch(serialName) + serialID, _ := strconv.Atoi(id[0]) - serialConfMap := QemuDevice{ - "id": serialID, - "type": params[serialName], - } + serialConfMap := QemuDevice{ + "id": serialID, + "type": params[serialName], + } - // And device config to serials map. - if len(serialConfMap) > 0 { - config.QemuSerials[serialID] = serialConfMap + // And device config to serials map. + if len(serialConfMap) > 0 { + config.QemuSerials[serialID] = serialConfMap + } } } @@ -609,26 +615,29 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } - for _, usbName := range usbNames { - usbConfStr := params[usbName] - usbConfList := strings.Split(usbConfStr.(string), ",") - id := rxDeviceID.FindStringSubmatch(usbName) - usbID, _ := strconv.Atoi(id[0]) - _, host := ParseSubConf(usbConfList[0], "=") - - usbConfMap := QemuDevice{ - "id": usbID, - "host": host, - } + if len(usbNames) > 0 { + config.QemuUsbs = QemuDevices{} + for _, usbName := range usbNames { + usbConfStr := params[usbName] + usbConfList := strings.Split(usbConfStr.(string), ",") + id := rxDeviceID.FindStringSubmatch(usbName) + usbID, _ := strconv.Atoi(id[0]) + _, host := ParseSubConf(usbConfList[0], "=") + + usbConfMap := QemuDevice{ + "id": usbID, + "host": host, + } - usbConfMap.readDeviceConfig(usbConfList[1:]) - if usbConfMap["usb3"] == 1 { - usbConfMap["usb3"] = true - } + usbConfMap.readDeviceConfig(usbConfList[1:]) + if usbConfMap["usb3"] == 1 { + usbConfMap["usb3"] = true + } - // And device config to usbs map. - if len(usbConfMap) > 0 { - config.QemuUsbs[usbID] = usbConfMap + // And device config to usbs map. + if len(usbConfMap) > 0 { + config.QemuUsbs[usbID] = usbConfMap + } } } @@ -641,18 +650,21 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } - for _, hostPCIname := range hostPCInames { - hostPCIConfStr := params[hostPCIname] - hostPCIConfList := strings.Split(hostPCIConfStr.(string), ",") - id := rxPCIName.FindStringSubmatch(hostPCIname) - hostPCIID, _ := strconv.Atoi(id[0]) - hostPCIConfMap := QemuDevice{ - "id": hostPCIID, - } - hostPCIConfMap.readDeviceConfig(hostPCIConfList) - // And device config to usbs map. - if len(hostPCIConfMap) > 0 { - config.QemuPCIDevices[hostPCIID] = hostPCIConfMap + if len(hostPCInames) > 0 { + config.QemuPCIDevices = QemuDevices{} + for _, hostPCIname := range hostPCInames { + hostPCIConfStr := params[hostPCIname] + hostPCIConfList := strings.Split(hostPCIConfStr.(string), ",") + id := rxPCIName.FindStringSubmatch(hostPCIname) + hostPCIID, _ := strconv.Atoi(id[0]) + hostPCIConfMap := QemuDevice{ + "id": hostPCIID, + } + hostPCIConfMap.readDeviceConfig(hostPCIConfList) + // And device config to usbs map. + if len(hostPCIConfMap) > 0 { + config.QemuPCIDevices[hostPCIID] = hostPCIConfMap + } } } From 70d28959042ea46c53ea7eaf17be7c6efcd580f8 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 11:12:46 +0000 Subject: [PATCH 086/191] fix: discard not set to true --- proxmox/config_qemu_disk.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 48427dc0..41b7aeaa 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -327,7 +327,9 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { continue } if e[0] == "discard" { - disk.Discard, _ = strconv.ParseBool(e[1]) + if e[1] == "on" { + disk.Discard = true + } continue } if e[0] == "iops_rd" { From e2022c79df05dfe0eb435e29106d5e1818148fc2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 12:27:09 +0000 Subject: [PATCH 087/191] fix: make replicate true by default --- proxmox/config_qemu_disk.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 41b7aeaa..95b93a8b 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -313,6 +313,9 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } } + // Replicate defaults to true + disk.Replicate = true + for _, e := range settings { if e[0] == "aio" { disk.AsyncIO = QemuDiskAsyncIO(e[1]) From 813adfa4509196efbaa4559a06e65bb8c23be026 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 16 Mar 2023 18:40:33 +0000 Subject: [PATCH 088/191] fix: CdRom not properly converted to struct --- proxmox/config_qemu_disk.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 95b93a8b..007193b8 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -53,7 +53,7 @@ func (cdRom QemuCdRom) mapToApiValues() string { } func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { - if !settings.Passthrough { + if settings.File != "" { return &QemuCdRom{ Iso: &IsoFile{ Storage: settings.Storage, @@ -62,7 +62,7 @@ func (QemuCdRom) mapToStruct(settings qemuCdRom) *QemuCdRom { }, } } - return &QemuCdRom{Passthrough: false} + return &QemuCdRom{Passthrough: settings.Passthrough} } func (cdRom QemuCdRom) Validate() error { @@ -102,10 +102,10 @@ func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { return nil } if settings[0][0] == "none" { - return &qemuCdRom{} + return &qemuCdRom{CdRom: true} } if settings[0][0] == "cdrom" { - return &qemuCdRom{Passthrough: true} + return &qemuCdRom{CdRom: true, Passthrough: true} } tmpStorage := strings.Split(settings[0][0], ":") if len(tmpStorage) > 1 { From d8cbbdc680f20b24e24757e3f2bd077fc553d853 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:43:05 +0000 Subject: [PATCH 089/191] fix: missing `Replicate` on `QemuVirtIOPassthrough` --- proxmox/config_qemu_disk_virtio.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 8641ed87..d5f068e2 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -201,6 +201,7 @@ type QemuVirtIOPassthrough struct { File string `json:"file"` IOThread bool `json:"iothread"` ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size"` //size is only returned and setting it has no effect } @@ -215,6 +216,7 @@ func (passthrough *QemuVirtIOPassthrough) convertDataStructure() *qemuDisk { File: passthrough.File, IOThread: passthrough.IOThread, ReadOnly: passthrough.ReadOnly, + Replicate: passthrough.Replicate, Serial: passthrough.Serial, Type: virtIO, } @@ -292,6 +294,7 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { File: tmpDisk.File, IOThread: tmpDisk.IOThread, ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, Serial: tmpDisk.Serial, Size: tmpDisk.Size, }} From 8dab836d7af8eb40726c6cc078f3894d9095228c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:49:09 +0000 Subject: [PATCH 090/191] test: add test for mapping `ConfigQemu.Disks` from Api values --- proxmox/config_qemu_test.go | 1764 +++++++++++++++++++++++++++++++++++ 1 file changed, 1764 insertions(+) diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 68a10e68..3e73d1a4 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -9,6 +9,1770 @@ import ( "github.com/stretchr/testify/require" ) +func Test_ConfigQemu_mapToStruct(t *testing.T) { + uint2 := uint(2) + uint31 := uint(31) + uint47 := uint(47) + uint53 := uint(53) + tests := []struct { + name string + input map[string]interface{} + output *ConfigQemu + err error + }{ + // TODO add test cases for all other items of ConfigQemu{} + // Disks Ide CdRom + {name: "Disks Ide CdRom none", + input: map[string]interface{}{"ide1": "none,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + }, + {name: "Disks Ide CdRom passthrough", + input: map[string]interface{}{"ide2": "cdrom,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + }, + {name: "Disks Ide CdRom iso", + input: map[string]interface{}{"ide3": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }}}}}}, + }, + // Disks Ide CloudInit + {name: "Disks Ide CloudInit", + input: map[string]interface{}{"ide0": "Test:100/vm-100-cloudinit.raw,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{ + Format: QemuDiskFormat_Raw, + Storage: "Test", + }}}}}, + }, + // Disks Ide Disk + {name: "Disks Ide Disk", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk ALL", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_wr=15,iops_wr_max=14,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57, Concurrent: 1.46}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 12}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, Concurrent: 15}, + }, + }, + Cache: QemuDiskCache_WriteThrough, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: false, + Serial: "disk-9763", + Size: 1032, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk aio", + input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,aio=io_uring"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk backup", + input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: false, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk cache", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,cache=writethrough"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Cache: QemuDiskCache_WriteThrough, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk discard", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk iops_rd", + input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,iops_rd=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 12}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk iops_rd_max", + input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,iops_rd_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk iops_wr", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,iops_wr=15"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 15}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk iops_wr_max", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,iops_wr_max=14"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk mbps_rd", + input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,mbps_rd=1.46"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.46}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk mbps_rd_max", + input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,mbps_rd_max=3.57"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk mbps_wr", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,mbps_wr=2.68"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.68}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk mbps_wr_max", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,mbps_wr_max=4.55"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk replicate", + input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: false, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk serial", + input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Serial: "disk-9763", + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk size", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,size=1032G"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Size: 1032, + Storage: "test2", + }}}}}, + }, + {name: "Disks Ide Disk ssd", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, + // Disks Ide Passthrough + {name: "Disks Ide Passthrough", + input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough All", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + Serial: "disk-9763", + Size: 1, + }}}}}, + }, + {name: "Disks Ide Passthrough aio", + input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough backup", + input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: false, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough cache", + input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,cache=unsafe"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Cache: QemuDiskCache_Unsafe, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough discard", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough iops_rd", + input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough iops_rd_max", + input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough iops_wr", + input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough iops_wr_max", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough mbps_rd", + input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough mbps_rd_max", + input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough mbps_wr", + input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough mbps_wr_max", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Ide Passthrough replicate", + input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + }}}}}, + }, + {name: "Disks Ide Passthrough serial", + input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "disk-9763", + }}}}}, + }, + {name: "Disks Ide Passthrough size", + input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,size=1G"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Size: 1, + }}}}}, + }, + {name: "Disks Ide Passthrough ssd", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + // Disks Sata CdRom + {name: "Disks Sata CdRom none", + input: map[string]interface{}{"sata5": "none,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + }, + {name: "Disks Sata CdRom passthrough", + input: map[string]interface{}{"sata4": "cdrom,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + }, + {name: "Disks Sata CdRom iso", + input: map[string]interface{}{"sata3": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }}}}}}, + }, + // Disks Sata CloudInit + {name: "Disks Sata CloudInit", + input: map[string]interface{}{"sata0": "Test:100/vm-100-cloudinit.raw,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{ + Format: QemuDiskFormat_Raw, + Storage: "Test", + }}}}}, + }, + // Disks Sata Disk + {name: "Disks Sata Disk", + input: map[string]interface{}{"sata0": "test2:100/vm-100-disk-47.qcow2"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk ALL", + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk aio", + input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,aio=native"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk backup", + input: map[string]interface{}{"sata3": "test2:100/vm-100-disk-47.qcow2,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: false, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk cache", + input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,cache=none"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Cache: QemuDiskCache_None, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk discard", + input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk iops_rd", + input: map[string]interface{}{"sata0": "test2:100/vm-100-disk-47.qcow2,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk iops_rd_max", + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk iops_wr", + input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk iops_wr_max", + input: map[string]interface{}{"sata3": "test2:100/vm-100-disk-47.qcow2,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk mbps_rd", + input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk mbps_rd_max", + input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk mbps_wr", + input: map[string]interface{}{"sata0": "test2:100/vm-100-disk-47.qcow2,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}, + }, + }, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk mbps_wr_max", + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk replicate", + input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: false, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk serial", + input: map[string]interface{}{"sata3": "test2:100/vm-100-disk-47.qcow2,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Serial: "disk-9763", + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk size", + input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,size=32G"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Size: 32, + Storage: "test2", + }}}}}, + }, + {name: "Disks Sata Disk ssd", + input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, + // Disks Sata Passthrough + {name: "Disks Sata Passthrough", + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough All", + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + Serial: "disk-9763", + Size: 1, + }}}}}, + }, + {name: "Disks Sata Passthrough aio", + input: map[string]interface{}{"sata2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough backup", + input: map[string]interface{}{"sata3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: false, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough cache", + input: map[string]interface{}{"sata4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,cache=directsync"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Cache: QemuDiskCache_DirectSync, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough discard", + input: map[string]interface{}{"sata5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough iops_rd", + input: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough iops_rd_max", + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough iops_wr", + input: map[string]interface{}{"sata2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough iops_wr_max", + input: map[string]interface{}{"sata3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough mbps_rd", + input: map[string]interface{}{"sata4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough mbps_rd_max", + input: map[string]interface{}{"sata5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough mbps_wr", + input: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough mbps_wr_max", + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Sata Passthrough replicate", + input: map[string]interface{}{"sata2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + }}}}}, + }, + {name: "Disks Sata Passthrough serial", + input: map[string]interface{}{"sata3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "disk-9763", + }}}}}, + }, + {name: "Disks Sata Passthrough size", + input: map[string]interface{}{"sata4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,size=1G"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Size: 1, + }}}}}, + }, + {name: "Disks Sata Passthrough ssd", + input: map[string]interface{}{"sata5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + // Disks Scsi CdRom + {name: "Disks Scsi CdRom none", + input: map[string]interface{}{"scsi30": "none,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_30: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + }, + {name: "Disks Scsi CdRom passthrough", + input: map[string]interface{}{"scsi29": "cdrom,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_29: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + }, + {name: "Disks Scsi CdRom iso", + input: map[string]interface{}{"scsi28": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_28: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }}}}}}, + }, + // Disks Scsi CloudInit + {name: "Disks Scsi CloudInit", + input: map[string]interface{}{"scsi0": "Test:100/vm-100-cloudinit.raw,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{ + Format: QemuDiskFormat_Raw, + Storage: "Test", + }}}}}, + }, + // Disks Scsi Disk + {name: "Disks Scsi Disk", + input: map[string]interface{}{"scsi0": "test:100/vm-100-disk-2.qcow2"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk ALL", + input: map[string]interface{}{"scsi1": "test:100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_WriteBack, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk aio", + input: map[string]interface{}{"scsi2": "test:100/vm-100-disk-2.qcow2,aio=threads"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk backup", + input: map[string]interface{}{"scsi3": "test:100/vm-100-disk-2.qcow2,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: false, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk cache", + input: map[string]interface{}{"scsi4": "test:100/vm-100-disk-2.qcow2,cache=writeback"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Cache: QemuDiskCache_WriteBack, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk discard", + input: map[string]interface{}{"scsi5": "test:100/vm-100-disk-2.qcow2,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk iops_rd", + input: map[string]interface{}{"scsi6": "test:100/vm-100-disk-2.qcow2,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk iops_rd_max", + input: map[string]interface{}{"scsi7": "test:100/vm-100-disk-2.qcow2,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk iops_wr", + input: map[string]interface{}{"scsi8": "test:100/vm-100-disk-2.qcow2,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk iops_wr_max", + input: map[string]interface{}{"scsi9": "test:100/vm-100-disk-2.qcow2,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk iothread", + input: map[string]interface{}{"scsi10": "test:100/vm-100-disk-2.qcow2,iothread=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + IOThread: true, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk mbps_rd", + input: map[string]interface{}{"scsi11": "test:100/vm-100-disk-2.qcow2,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk mbps_rd_max", + input: map[string]interface{}{"scsi12": "test:100/vm-100-disk-2.qcow2,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk mbps_wr", + input: map[string]interface{}{"scsi13": "test:100/vm-100-disk-2.qcow2,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk mbps_wr_max", + input: map[string]interface{}{"scsi14": "test:100/vm-100-disk-2.qcow2,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk replicate", + input: map[string]interface{}{"scsi15": "test:100/vm-100-disk-2.qcow2,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: false, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk ro", + input: map[string]interface{}{"scsi16": "test:100/vm-100-disk-2.qcow2,ro=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + ReadOnly: true, + Replicate: true, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk serial", + input: map[string]interface{}{"scsi17": "test:100/vm-100-disk-2.qcow2,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Serial: "disk-9763", + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk size", + input: map[string]interface{}{"scsi18": "test:100/vm-100-disk-2.qcow2,size=32G"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Size: 32, + Storage: "test", + }}}}}, + }, + {name: "Disks Scsi Disk ssd", + input: map[string]interface{}{"scsi19": "test:100/vm-100-disk-2.qcow2,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, + // Disks Scsi Passthrough + {name: "Disks Scsi Passthrough", + input: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough All", + input: map[string]interface{}{"scsi1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 1, + }}}}}, + }, + {name: "Disks Scsi Passthrough aio", + input: map[string]interface{}{"scsi2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough backup", + input: map[string]interface{}{"scsi3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: false, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough cache", + input: map[string]interface{}{"scsi4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,cache=none"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Cache: QemuDiskCache_None, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough discard", + input: map[string]interface{}{"scsi5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough iops_rd", + input: map[string]interface{}{"scsi6": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough iops_rd_max", + input: map[string]interface{}{"scsi7": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough iops_wr", + input: map[string]interface{}{"scsi8": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough iops_wr_max", + input: map[string]interface{}{"scsi9": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough iothread", + input: map[string]interface{}{"scsi10": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iothread=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough mbps_rd", + input: map[string]interface{}{"scsi11": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough mbps_rd_max", + input: map[string]interface{}{"scsi12": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough mbps_wr", + input: map[string]interface{}{"scsi13": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough mbps_wr_max", + input: map[string]interface{}{"scsi14": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough replicate", + input: map[string]interface{}{"scsi15": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + }}}}}, + }, + {name: "Disks Scsi Passthrough ro", + input: map[string]interface{}{"scsi16": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,ro=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + ReadOnly: true, + Replicate: true, + }}}}}, + }, + {name: "Disks Scsi Passthrough serial", + input: map[string]interface{}{"scsi17": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "disk-9763", + }}}}}, + }, + {name: "Disks Scsi Passthrough size", + input: map[string]interface{}{"scsi18": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,size=1G"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Size: 1, + }}}}}, + }, + {name: "Disks Scsi Passthrough ssd", + input: map[string]interface{}{"scsi19": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + // VirtIO CdRom + {name: "Disks VirtIO CdRom none", + input: map[string]interface{}{"virtio11": "none,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + }, + {name: "Disks VirtIO CdRom passthrough", + input: map[string]interface{}{"virtio10": "cdrom,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + }, + {name: "Disks VirtIO CdRom iso", + input: map[string]interface{}{"virtio9": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }}}}}}, + }, + // Disks VirtIO CloudInit + {name: "Disks VirtIO CloudInit", + input: map[string]interface{}{"virtio0": "Test:100/vm-100-cloudinit.raw,media=cdrom"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{ + Format: QemuDiskFormat_Raw, + Storage: "Test", + }}}}}, + }, + // Disks VirtIO Disk + {name: "Disks VirtIO Disk", + input: map[string]interface{}{"virtio0": "test2:100/vm-100-disk-31.qcow2"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk ALL", + input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk aio", + input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,aio=io_uring"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk backup", + input: map[string]interface{}{"virtio3": "test2:100/vm-100-disk-31.qcow2,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: false, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk cache", + input: map[string]interface{}{"virtio4": "test2:100/vm-100-disk-31.qcow2,cache=directsync"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Cache: QemuDiskCache_DirectSync, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk discard", + input: map[string]interface{}{"virtio5": "test2:100/vm-100-disk-31.qcow2,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iops_rd", + input: map[string]interface{}{"virtio6": "test2:100/vm-100-disk-31.qcow2,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iops_rd_max", + input: map[string]interface{}{"virtio7": "test2:100/vm-100-disk-31.qcow2,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}, + }, + }, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iops_wr", + input: map[string]interface{}{"virtio8": "test2:100/vm-100-disk-31.qcow2,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iops_wr_max", + input: map[string]interface{}{"virtio9": "test2:100/vm-100-disk-31.qcow2,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iothread", + input: map[string]interface{}{"virtio10": "test2:100/vm-100-disk-31.qcow2,iothread=1"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + IOThread: true, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk mbps_rd", + input: map[string]interface{}{"virtio11": "test2:100/vm-100-disk-31.qcow2,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}, + }, + }, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk mbps_rd_max", + input: map[string]interface{}{"virtio12": "test2:100/vm-100-disk-31.qcow2,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk mbps_wr", + input: map[string]interface{}{"virtio13": "test2:100/vm-100-disk-31.qcow2,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk mbps_wr_max", + input: map[string]interface{}{"virtio14": "test2:100/vm-100-disk-31.qcow2,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk replicate", + input: map[string]interface{}{"virtio15": "test2:100/vm-100-disk-31.qcow2,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: false, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk ro", + input: map[string]interface{}{"virtio0": "test2:100/vm-100-disk-31.qcow2,ro=1"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + ReadOnly: true, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk serial", + input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Serial: "disk-9763", + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk size", + input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,size=32G"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: &uint31, + Replicate: true, + Size: 32, + Storage: "test2", + }}}}}, + }, + // Disks VirtIO Passthrough + {name: "Disks VirtIO Passthrough", + input: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough ALL", + input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 1, + }}}}}, + }, + {name: "Disks VirtIO Passthrough aio", + input: map[string]interface{}{"virtio2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough backup", + input: map[string]interface{}{"virtio3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: false, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough cache", + input: map[string]interface{}{"virtio4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,cache=unsafe"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Cache: QemuDiskCache_Unsafe, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough discard", + input: map[string]interface{}{"virtio5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,discard=on"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough iops_rd", + input: map[string]interface{}{"virtio6": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd=10"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough iops_rd_max", + input: map[string]interface{}{"virtio7": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max=12"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough iops_wr", + input: map[string]interface{}{"virtio8": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough iops_wr_max", + input: map[string]interface{}{"virtio9": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max=13"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough iothread", + input: map[string]interface{}{"virtio10": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iothread=1"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough mbps_rd", + input: map[string]interface{}{"virtio11": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough mbps_rd_max", + input: map[string]interface{}{"virtio12": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough mbps_wr", + input: map[string]interface{}{"virtio13": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough mbps_wr_max", + input: map[string]interface{}{"virtio14": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough replicate", + input: map[string]interface{}{"virtio15": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,replicate=0"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + }}}}}, + }, + {name: "Disks VirtIO Passthrough ro", + input: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,ro=1"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + ReadOnly: true, + Replicate: true, + }}}}}, + }, + {name: "Disks VirtIO Passthrough serial", + input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,serial=disk-9763"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "disk-9763", + }}}}}, + }, + {name: "Disks VirtIO Passthrough size", + input: map[string]interface{}{"virtio2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,size=1G"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Size: 1, + }}}}}, + }, + // Iso + {name: "Iso", + input: map[string]interface{}{"ide2": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, + output: &ConfigQemu{ + Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{ + Iso: &IsoFile{ + File: "debian-11.0.0-amd64-netinst.iso", + Storage: "local", + Size: "377M", + }, + }}}}, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + output, err := ConfigQemu{}.mapToStruct(test.input) + if err != nil { + require.Equal(t, test.err, err, test.name) + } else { + require.Equal(t, test.output, output, test.name) + } + }) + } +} func Test_ConfigQemu_Validate(t *testing.T) { BandwidthValid0 := QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ From c36bc0fe2d339f57b1c50550343f2b2c5e784743 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 18 Mar 2023 17:00:26 +0000 Subject: [PATCH 091/191] refactor: disk migration replace `*Client.MoveQemuDisk` with `MoveQemuDisk` --- proxmox/client.go | 1 + proxmox/config_qemu.go | 2 +- proxmox/config_qemu_disk.go | 132 ++++++++++++++++--- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_test.go | 199 ++++++++++++++++++++++++++++- proxmox/config_qemu_disk_virtio.go | 2 +- 8 files changed, 321 insertions(+), 21 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index dffd7b7b..2b73d67f 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -788,6 +788,7 @@ func (c *Client) MoveLxcDisk(vmr *VmRef, disk string, storage string) (exitStatu return } +// DEPRECATED use MoveQemuDisk() instead. // MoveQemuDisk - Move a disk from one storage to another func (c *Client) MoveQemuDisk(vmr *VmRef, disk string, storage string) (exitStatus interface{}, err error) { if disk == "" { diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 7bc9f87b..611de37b 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -707,7 +707,7 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef if markedDisks != nil { for _, e := range markedDisks.Move { - _, err = client.MoveQemuDisk(vmr, e.Id, e.Storage) + _, err = e.move(true, vmr, client) if err != nil { return } diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 007193b8..e44aec8e 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -576,6 +576,65 @@ func (format QemuDiskFormat) Validate() error { return QemuDiskFormat("").Error() } +type QemuDiskId string + +const ERROR_QemuDiskId_Invalid string = "invalid Disk ID" + +func (id QemuDiskId) Validate() error { + if len(id) >= 7 { + if id[0:6] == "virtio" { + if id[6:] != "0" && strings.HasPrefix(string(id[6:]), "0") { + return errors.New(ERROR_QemuDiskId_Invalid) + } + number, err := strconv.Atoi(string(id[6:])) + if err != nil { + return errors.New(ERROR_QemuDiskId_Invalid) + } + if number >= 0 && number <= 15 { + return nil + } + } + } + if len(id) >= 5 { + if id[0:4] == "sata" { + if id[4:] != "0" && strings.HasPrefix(string(id[4:]), "0") { + return errors.New(ERROR_QemuDiskId_Invalid) + } + number, err := strconv.Atoi(string(id[4:])) + if err != nil { + return errors.New(ERROR_QemuDiskId_Invalid) + } + if number >= 0 && number <= 5 { + return nil + } + } + if id[0:4] == "scsi" { + if id[4:] != "0" && strings.HasPrefix(string(id[4:]), "0") { + return errors.New(ERROR_QemuDiskId_Invalid) + } + number, err := strconv.Atoi(string(id[4:])) + if err != nil { + return errors.New(ERROR_QemuDiskId_Invalid) + } + if number >= 0 && number <= 30 { + return nil + } + } + } + if len(id) == 4 { + if id[0:3] == "ide" { + number, err := strconv.Atoi(string(id[3])) + if err != nil { + return errors.New(ERROR_QemuDiskId_Invalid) + } + if number >= 0 && number <= 3 { + return nil + } + } + } + return errors.New(ERROR_QemuDiskId_Invalid) +} + type QemuDiskSerial string const ( @@ -597,7 +656,7 @@ func (serial QemuDiskSerial) Validate() error { } type qemuDiskResize struct { - Id string + Id QemuDiskId SizeInGigaBytes uint } @@ -608,8 +667,36 @@ func (disk qemuDiskResize) resize(vmr *VmRef, client *Client) (exitStatus string } type qemuDiskShort struct { + Format *QemuDiskFormat + Id QemuDiskId Storage string - Id string +} + +func (disk qemuDiskShort) mapToApiValues(delete bool) (params map[string]interface{}) { + params = map[string]interface{}{"disk": string(disk.Id), "storage": string(disk.Storage)} + if delete { + params["delete"] = "1" + } + if disk.Format != nil { + params["format"] = string(*disk.Format) + } + return +} + +func (disk qemuDiskShort) move(delete bool, vmr *VmRef, client *Client) (exitStatus interface{}, err error) { + return client.PostWithTask(disk.mapToApiValues(delete), fmt.Sprintf("/nodes/%s/%s/%d/move_disk", vmr.node, vmr.vmType, vmr.vmId)) +} + +func (disk qemuDiskShort) Validate() (err error) { + if disk.Format != nil { + err = disk.Format.Validate() + if err != nil { + return + } + } + err = disk.Id.Validate() + // TODO validate storage when it has custom type + return } type qemuDiskType int @@ -628,35 +715,35 @@ type qemuStorage struct { Passthrough *qemuDisk } -func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID uint, id string, params map[string]interface{}, changes *qemuUpdateChanges) { +func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID uint, id QemuDiskId, params map[string]interface{}, changes *qemuUpdateChanges) { if storage == nil { return } // CDROM if storage.CdRom != nil { // Create or Update - params[id] = storage.CdRom.mapToApiValues() + params[string(id)] = storage.CdRom.mapToApiValues() return } else if currentStorage != nil && currentStorage.CdRom != nil && storage.CloudInit == nil && storage.Disk == nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, string(id)) return } // CloudInit if storage.CloudInit != nil { // Create or Update - params[id] = storage.CloudInit.mapToApiValues() + params[string(id)] = storage.CloudInit.mapToApiValues() return } else if currentStorage != nil && currentStorage.CloudInit != nil && storage.Disk == nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, string(id)) return } // Disk if storage.Disk != nil { if currentStorage == nil || currentStorage.Disk == nil { // Create - params[id] = storage.Disk.mapToApiValues(vmID, true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, true) return } else { if storage.Disk.Size >= currentStorage.Disk.Size { @@ -670,38 +757,39 @@ func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID ui if storage.Disk.Id == nil { storage.Disk.Id = currentStorage.Disk.Id } - if storage.Disk.Storage != currentStorage.Disk.Storage { + if storage.Disk.Storage != currentStorage.Disk.Storage || storage.Disk.Format != currentStorage.Disk.Format { changes.Move = append(changes.Move, qemuDiskShort{ + Format: &storage.Disk.Format, Id: id, Storage: storage.Disk.Storage, }) } - params[id] = storage.Disk.mapToApiValues(vmID, false) + params[string(id)] = storage.Disk.mapToApiValues(vmID, false) } else { // Delete and Create // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. - params[id] = storage.Disk.mapToApiValues(vmID, true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, true) } return } } else if currentStorage != nil && currentStorage.Disk != nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, string(id)) return } // Passthrough if storage.Passthrough != nil { // Create or Update - params[id] = storage.Passthrough.mapToApiValues(0, false) + params[string(id)] = storage.Passthrough.mapToApiValues(0, false) return } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = AddToList(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, string(id)) return } // Delete if no subtype was specified if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, id) + changes.Delete = AddToList(changes.Delete, string(id)) } } @@ -813,3 +901,17 @@ func diskSubtypeSet(set bool) error { } return nil } + +func MoveQemuDisk(format *QemuDiskFormat, diskId QemuDiskId, storage string, deleteAfterMove bool, vmr *VmRef, client *Client) (err error) { + disk := qemuDiskShort{ + Format: format, + Id: diskId, + Storage: storage, + } + err = disk.Validate() + if err != nil { + return + } + _, err = disk.move(deleteAfterMove, vmr, client) + return +} diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 5b0491db..9fda8389 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -56,7 +56,7 @@ func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "ide"+strconv.Itoa(int(i)), params, changes) + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("ide"+strconv.Itoa(int(i))), params, changes) } } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 2dcd0732..2ad8a0b0 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -58,7 +58,7 @@ func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "sata"+strconv.Itoa(int(i)), params, changes) + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("sata"+strconv.Itoa(int(i))), params, changes) } } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 6cb5c12d..7cff0dc2 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -87,7 +87,7 @@ func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "scsi"+strconv.Itoa(int(i)), params, changes) + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("scsi"+strconv.Itoa(int(i))), params, changes) } } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 99de3fdb..e6d9188a 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -319,7 +319,7 @@ func Test_QemuDiskCache_Validate(t *testing.T) { } func Test_QemuDiskFormat_Validate(t *testing.T) { - testData := []struct { + tests := []struct { name string input QemuDiskFormat err error @@ -337,6 +337,98 @@ func Test_QemuDiskFormat_Validate(t *testing.T) { {name: "Invalid 01", input: "invalid value", err: QemuDiskFormat("").Error()}, {name: "Invalid 02", input: "!@#$", err: QemuDiskFormat("").Error()}, } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + +func Test_QemuDiskId_Validate(t *testing.T) { + testData := []struct { + name string + input QemuDiskId + err error + }{ + // Invalid + {name: "Invalid 00", input: "ide4", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 01", input: "ide01", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 02", input: "ide10", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 03", input: "sata6", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 04", input: "sata01", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 05", input: "sata10", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 06", input: "scsi31", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 07", input: "scsi01", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 08", input: "scsi100", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 09", input: "virtio16", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 10", input: "virtio01", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 11", input: "virtio100", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 12", input: "bla", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 13", input: "invalid value", err: errors.New(ERROR_QemuDiskId_Invalid)}, + {name: "Invalid 14", input: "!@#$", err: errors.New(ERROR_QemuDiskId_Invalid)}, + // Valid + {name: "Valid 01", input: "ide0"}, + {name: "Valid 02", input: "ide1"}, + {name: "Valid 03", input: "ide2"}, + {name: "Valid 04", input: "ide3"}, + {name: "Valid 05", input: "sata0"}, + {name: "Valid 06", input: "sata1"}, + {name: "Valid 07", input: "sata2"}, + {name: "Valid 08", input: "sata3"}, + {name: "Valid 09", input: "sata4"}, + {name: "Valid 10", input: "sata5"}, + {name: "Valid 11", input: "scsi0"}, + {name: "Valid 12", input: "scsi1"}, + {name: "Valid 13", input: "scsi2"}, + {name: "Valid 14", input: "scsi3"}, + {name: "Valid 15", input: "scsi4"}, + {name: "Valid 16", input: "scsi5"}, + {name: "Valid 17", input: "scsi6"}, + {name: "Valid 18", input: "scsi7"}, + {name: "Valid 19", input: "scsi8"}, + {name: "Valid 20", input: "scsi9"}, + {name: "Valid 21", input: "scsi10"}, + {name: "Valid 22", input: "scsi11"}, + {name: "Valid 23", input: "scsi12"}, + {name: "Valid 24", input: "scsi13"}, + {name: "Valid 25", input: "scsi14"}, + {name: "Valid 26", input: "scsi15"}, + {name: "Valid 27", input: "scsi16"}, + {name: "Valid 28", input: "scsi17"}, + {name: "Valid 29", input: "scsi18"}, + {name: "Valid 30", input: "scsi19"}, + {name: "Valid 31", input: "scsi20"}, + {name: "Valid 32", input: "scsi21"}, + {name: "Valid 33", input: "scsi22"}, + {name: "Valid 34", input: "scsi23"}, + {name: "Valid 35", input: "scsi24"}, + {name: "Valid 36", input: "scsi25"}, + {name: "Valid 37", input: "scsi26"}, + {name: "Valid 38", input: "scsi27"}, + {name: "Valid 39", input: "scsi28"}, + {name: "Valid 40", input: "scsi29"}, + {name: "Valid 41", input: "scsi30"}, + {name: "Valid 42", input: "virtio0"}, + {name: "Valid 43", input: "virtio1"}, + {name: "Valid 44", input: "virtio2"}, + {name: "Valid 45", input: "virtio3"}, + {name: "Valid 46", input: "virtio4"}, + {name: "Valid 47", input: "virtio5"}, + {name: "Valid 48", input: "virtio6"}, + {name: "Valid 49", input: "virtio7"}, + {name: "Valid 50", input: "virtio8"}, + {name: "Valid 51", input: "virtio9"}, + {name: "Valid 52", input: "virtio10"}, + {name: "Valid 53", input: "virtio11"}, + {name: "Valid 54", input: "virtio12"}, + {name: "Valid 55", input: "virtio13"}, + {name: "Valid 56", input: "virtio14"}, + {name: "Valid 57", input: "virtio15"}, + } for _, test := range testData { t.Run(test.name, func(*testing.T) { if test.err != nil { @@ -369,3 +461,108 @@ func Test_QemuDiskSerial_Validate(t *testing.T) { }) } } + +func Test_qemuDiskShort_mapToApiValues(t *testing.T) { + format_Raw := QemuDiskFormat_Raw + format_Qcow2 := QemuDiskFormat_Qcow2 + tests := []struct { + name string + delete bool + input qemuDiskShort + output map[string]interface{} + }{ + {name: "ALL", + delete: true, + input: qemuDiskShort{ + Format: &format_Raw, + Id: "ide0", + Storage: "test0", + }, + output: map[string]interface{}{ + "disk": "ide0", + "storage": "test0", + "delete": "1", + "format": "raw", + }, + }, + {name: "Format nil", + delete: true, + input: qemuDiskShort{ + Id: "sata4", + Storage: "aaa0", + }, + output: map[string]interface{}{ + "disk": "sata4", + "storage": "aaa0", + "delete": "1", + }, + }, + {name: "Delete false", + input: qemuDiskShort{ + Format: &format_Qcow2, + Id: "scsi10", + Storage: "test0", + }, + output: map[string]interface{}{ + "format": "qcow2", + "disk": "scsi10", + "storage": "test0", + }, + }, + {name: "MINIMAL", + input: qemuDiskShort{ + Id: "virtio13", + Storage: "Test0", + }, + output: map[string]interface{}{ + "disk": "virtio13", + "storage": "Test0", + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.output, test.input.mapToApiValues(test.delete), test.name) + }) + } +} + +func Test_qemuDiskShort_Validate(t *testing.T) { + format_Raw := QemuDiskFormat_Raw + format_Invalid := QemuDiskFormat("invalid") + format_Empty := QemuDiskFormat("") + tests := []struct { + name string + input qemuDiskShort + err error + }{ + // TODO Add cases when Storage has a custom type + // Invalid + {name: "Invalid 00", input: qemuDiskShort{Format: &format_Invalid}, + err: QemuDiskFormat("").Error(), + }, + {name: "Invalid 01", input: qemuDiskShort{Format: &format_Empty}, + err: QemuDiskFormat("").Error(), + }, + {name: "Invalid 02", input: qemuDiskShort{Id: "invalid"}, + err: errors.New(ERROR_QemuDiskId_Invalid), + }, + // Valid + {name: "Valid 00", input: qemuDiskShort{ + Format: &format_Raw, + Id: "ide0", + }}, + {name: "Valid 01", input: qemuDiskShort{ + Id: "ide0", + }}, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index d5f068e2..df012dd4 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -70,7 +70,7 @@ func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, "virtio"+strconv.Itoa(int(i)), params, changes) + diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("virtio"+strconv.Itoa(int(i))), params, changes) } } From fda1d507a74cb0a9b72e72b161e620a37b596d94 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 18 Mar 2023 17:03:10 +0000 Subject: [PATCH 092/191] fix: format not set when creating and updating disk --- proxmox/config_qemu_disk.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index e44aec8e..f249403e 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -236,7 +236,9 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { if disk.Discard { settings = settings + ",discard=on" } - // format + if disk.Format != "" { + settings = settings + ",format=" + string(disk.Format) + } // media if disk.Bandwidth.Iops.ReadLimit.Concurrent != 0 { From 19a17f63b17ca4f104d096682ac42489f6f254d2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 19 Mar 2023 21:03:56 +0000 Subject: [PATCH 093/191] refactor: format only needs to be set during disk creation --- proxmox/config_qemu_disk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f249403e..2e7902f7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -236,7 +236,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { if disk.Discard { settings = settings + ",discard=on" } - if disk.Format != "" { + if disk.Format != "" && create { settings = settings + ",format=" + string(disk.Format) } // media From 670277e91e152ed28f6f30bbc50318fce69435b4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 19 Mar 2023 21:08:12 +0000 Subject: [PATCH 094/191] refactor: seperate disk marking logic for mapping logic --- proxmox/config_qemu.go | 37 ++++--- proxmox/config_qemu_disk.go | 109 ++++++++++++--------- proxmox/config_qemu_disk_ide.go | 33 ++++++- proxmox/config_qemu_disk_sata.go | 33 ++++++- proxmox/config_qemu_disk_scsi.go | 33 ++++++- proxmox/config_qemu_disk_test.go | 152 +++++++++++++++++++++++++++++ proxmox/config_qemu_disk_virtio.go | 33 ++++++- 7 files changed, 366 insertions(+), 64 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 611de37b..c0ed60bb 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -97,7 +97,7 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { if err != nil { return } - params, _, err := config.mapToApiValues(ConfigQemu{}) + params, err := config.mapToApiValues(ConfigQemu{}) if err != nil { return } @@ -182,7 +182,7 @@ func (config *ConfigQemu) defaults() { } -func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, markedDisks *qemuUpdateChanges, err error) { +func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, err error) { var itemsToDelete string @@ -299,15 +299,14 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[st // Disks if currentConfig.Disks != nil { if config.Disks != nil { - markedDisks = config.Disks.markDiskChanges(*currentConfig.Disks, uint(config.VmID), params) - if markedDisks.Delete != "" { - itemsToDelete = AddToList(itemsToDelete, markedDisks.Delete) - markedDisks.Delete = "" + delete := config.Disks.mapToApiValues(*currentConfig.Disks, uint(config.VmID), params) + if delete != "" { + itemsToDelete = AddToList(itemsToDelete, delete) } } } else { if config.Disks != nil { - config.Disks.mapToApiValues(uint(config.VmID), params) + config.Disks.mapToApiValues(QemuStorages{}, uint(config.VmID), params) } } @@ -700,12 +699,9 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef if err != nil { return } - params, markedDisks, err := newConfig.mapToApiValues(*currentConfig) - if err != nil { - return - } - if markedDisks != nil { + if currentConfig != nil { + markedDisks := newConfig.Disks.markDiskChanges(*currentConfig.Disks) for _, e := range markedDisks.Move { _, err = e.move(true, vmr, client) if err != nil { @@ -718,6 +714,13 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef return } } + // Moving disks changes the disk id. we need to get the config again if any disk was moved + if len(markedDisks.Move) != 0 { + currentConfig, err = NewConfigQemuFromApi(vmr, client) + if err != nil { + return + } + } } if newConfig.Node != currentConfig.Node { @@ -729,6 +732,16 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef vmr.SetNode(newConfig.Node) } + var params map[string]interface{} + if currentConfig != nil { + params, err = newConfig.mapToApiValues(*currentConfig) + } else { + params, err = newConfig.mapToApiValues(ConfigQemu{}) + } + if err != nil { + return + } + _, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") if err != nil { return diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 2e7902f7..118d316e 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -580,7 +580,9 @@ func (format QemuDiskFormat) Validate() error { type QemuDiskId string -const ERROR_QemuDiskId_Invalid string = "invalid Disk ID" +const ( + ERROR_QemuDiskId_Invalid string = "invalid Disk ID" +) func (id QemuDiskId) Validate() error { if len(id) >= 7 { @@ -637,6 +639,42 @@ func (id QemuDiskId) Validate() error { return errors.New(ERROR_QemuDiskId_Invalid) } +type qemuDiskMark struct { + Format QemuDiskFormat + Id QemuDiskId + Size uint + Storage string + Type qemuDiskType +} + +// Generate lists of disks that need to be moved and or resized +func (disk *qemuDiskMark) markChanges(currentDisk *qemuDiskMark, id QemuDiskId, changes *qemuUpdateChanges) { + if disk == nil || currentDisk == nil { + return + } + // Disk + if disk.Size >= currentDisk.Size { + // Update + if disk.Size > currentDisk.Size { + changes.Resize = append(changes.Resize, qemuDiskResize{ + Id: id, + SizeInGigaBytes: disk.Size, + }) + } + if disk.Storage != currentDisk.Storage || disk.Format != currentDisk.Format { + var format *QemuDiskFormat + if disk.Format != currentDisk.Format { + format = &disk.Format + } + changes.Move = append(changes.Move, qemuDiskShort{ + Format: format, + Id: id, + Storage: disk.Storage, + }) + } + } +} + type QemuDiskSerial string const ( @@ -668,6 +706,7 @@ func (disk qemuDiskResize) resize(vmr *VmRef, client *Client) (exitStatus string return client.PutWithTask(map[string]interface{}{"disk": disk.Id, "size": strconv.Itoa(int(disk.SizeInGigaBytes)) + "G"}, fmt.Sprintf("/nodes/%s/%s/%d/resize", vmr.node, vmr.vmType, vmr.vmId)) } +// TODO rename to qemuDiskMove type qemuDiskShort struct { Format *QemuDiskFormat Id QemuDiskId @@ -717,82 +756,64 @@ type qemuStorage struct { Passthrough *qemuDisk } -func (storage *qemuStorage) markDiskChanges(currentStorage *qemuStorage, vmID uint, id QemuDiskId, params map[string]interface{}, changes *qemuUpdateChanges) { +func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uint, id QemuDiskId, params map[string]interface{}, delete string) string { if storage == nil { - return + return delete } // CDROM if storage.CdRom != nil { // Create or Update params[string(id)] = storage.CdRom.mapToApiValues() - return + return delete } else if currentStorage != nil && currentStorage.CdRom != nil && storage.CloudInit == nil && storage.Disk == nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, string(id)) - return + return AddToList(delete, string(id)) } // CloudInit if storage.CloudInit != nil { // Create or Update params[string(id)] = storage.CloudInit.mapToApiValues() - return + return delete } else if currentStorage != nil && currentStorage.CloudInit != nil && storage.Disk == nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, string(id)) - return + return AddToList(delete, string(id)) } // Disk if storage.Disk != nil { if currentStorage == nil || currentStorage.Disk == nil { // Create params[string(id)] = storage.Disk.mapToApiValues(vmID, true) - return + return delete } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update - if storage.Disk.Size > currentStorage.Disk.Size { - changes.Resize = append(changes.Resize, qemuDiskResize{ - Id: id, - SizeInGigaBytes: storage.Disk.Size, - }) - } - if storage.Disk.Id == nil { - storage.Disk.Id = currentStorage.Disk.Id - } - if storage.Disk.Storage != currentStorage.Disk.Storage || storage.Disk.Format != currentStorage.Disk.Format { - changes.Move = append(changes.Move, qemuDiskShort{ - Format: &storage.Disk.Format, - Id: id, - Storage: storage.Disk.Storage, - }) - } + storage.Disk.Id = currentStorage.Disk.Id params[string(id)] = storage.Disk.mapToApiValues(vmID, false) } else { // Delete and Create // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. params[string(id)] = storage.Disk.mapToApiValues(vmID, true) } - return + return delete } } else if currentStorage != nil && currentStorage.Disk != nil && storage.Passthrough == nil { // Delete - changes.Delete = AddToList(changes.Delete, string(id)) - return + return AddToList(delete, string(id)) } // Passthrough if storage.Passthrough != nil { // Create or Update params[string(id)] = storage.Passthrough.mapToApiValues(0, false) - return + return delete } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete - changes.Delete = AddToList(changes.Delete, string(id)) - return + return AddToList(delete, string(id)) } // Delete if no subtype was specified if currentStorage != nil { - changes.Delete = AddToList(changes.Delete, string(id)) + return AddToList(delete, string(id)) } + return delete } type QemuStorages struct { @@ -802,19 +823,20 @@ type QemuStorages struct { VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` } -func (storages QemuStorages) mapToApiValues(vmID uint, params map[string]interface{}) { +func (storages QemuStorages) mapToApiValues(currentStorages QemuStorages, vmID uint, params map[string]interface{}) (delete string) { if storages.Ide != nil { - storages.Ide.mapToApiValues(nil, vmID, params, nil) + delete = storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, delete) } if storages.Sata != nil { - storages.Sata.mapToApiValues(nil, vmID, params, nil) + delete = storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, delete) } if storages.Scsi != nil { - storages.Scsi.mapToApiValues(nil, vmID, params, nil) + delete = storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, delete) } if storages.VirtIO != nil { - storages.VirtIO.mapToApiValues(nil, vmID, params, nil) + delete = storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, delete) } + return delete } func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { @@ -830,19 +852,19 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { return nil } -func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages, vmID uint, params map[string]interface{}) *qemuUpdateChanges { +func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages) *qemuUpdateChanges { changes := &qemuUpdateChanges{} if storages.Ide != nil { - storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, changes) + storages.Ide.markDiskChanges(currentStorages.Ide, changes) } if storages.Sata != nil { - storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, changes) + storages.Sata.markDiskChanges(currentStorages.Sata, changes) } if storages.Scsi != nil { - storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, changes) + storages.Scsi.markDiskChanges(currentStorages.Scsi, changes) } if storages.VirtIO != nil { - storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, changes) + storages.VirtIO.markDiskChanges(currentStorages.VirtIO, changes) } return changes } @@ -892,7 +914,6 @@ func (storages QemuStorages) Validate() (err error) { } type qemuUpdateChanges struct { - Delete string Move []qemuDiskShort Resize []qemuDiskResize } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 9fda8389..d6d641b9 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -48,7 +48,7 @@ type QemuIdeDisks struct { } // TODO write test -func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuIdeDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -56,8 +56,9 @@ func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("ide"+strconv.Itoa(int(i))), params, changes) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("ide"+strconv.Itoa(int(i))), params, delete) } + return delete } func (disks QemuIdeDisks) mapToIntMap() map[uint8]*QemuIdeStorage { @@ -95,6 +96,18 @@ func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { return nil } +func (disks QemuIdeDisks) markDiskChanges(currentDisks *QemuIdeDisks, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuIdeDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructureMark().markChanges(currentDiskMap[i].convertDataStructureMark(), QemuDiskId("ide"+strconv.Itoa(int(i))), changes) + } +} + func (disks QemuIdeDisks) Validate() (err error) { _, err = disks.validate() return @@ -176,6 +189,22 @@ func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { return &generalizedStorage } +// converts to qemuDiskMark +func (storage *QemuIdeStorage) convertDataStructureMark() *qemuDiskMark { + if storage == nil { + return nil + } + if storage.Disk != nil { + return &qemuDiskMark{ + Format: storage.Disk.Format, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + Type: ide, + } + } + return nil +} + // TODO write test func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 2ad8a0b0..b45570c9 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -50,7 +50,7 @@ type QemuSataDisks struct { } // TODO write test -func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuSataDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -58,8 +58,9 @@ func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("sata"+strconv.Itoa(int(i))), params, changes) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("sata"+strconv.Itoa(int(i))), params, delete) } + return delete } func (disks QemuSataDisks) mapToIntMap() map[uint8]*QemuSataStorage { @@ -107,6 +108,18 @@ func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { return nil } +func (disks QemuSataDisks) markDiskChanges(currentDisks *QemuSataDisks, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuSataDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructureMark().markChanges(currentDiskMap[i].convertDataStructureMark(), QemuDiskId("sata"+strconv.Itoa(int(i))), changes) + } +} + func (disks QemuSataDisks) Validate() (err error) { _, err = disks.validate() return @@ -188,6 +201,22 @@ func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { return &generalizedStorage } +// converts to qemuDiskMark +func (storage *QemuSataStorage) convertDataStructureMark() *qemuDiskMark { + if storage == nil { + return nil + } + if storage.Disk != nil { + return &qemuDiskMark{ + Format: storage.Disk.Format, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + Type: ide, + } + } + return nil +} + // TODO write test func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 7cff0dc2..c9407e2f 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -79,7 +79,7 @@ type QemuScsiDisks struct { } // TODO write test -func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuScsiDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -87,8 +87,9 @@ func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("scsi"+strconv.Itoa(int(i))), params, changes) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("scsi"+strconv.Itoa(int(i))), params, delete) } + return delete } func (disks QemuScsiDisks) mapToIntMap() map[uint8]*QemuScsiStorage { @@ -261,6 +262,18 @@ func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { return nil } +func (disks QemuScsiDisks) markDiskChanges(currentDisks *QemuScsiDisks, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuScsiDisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructureMark().markChanges(currentDiskMap[i].convertDataStructureMark(), QemuDiskId("scsi"+strconv.Itoa(int(i))), changes) + } +} + func (disks QemuScsiDisks) Validate() (err error) { _, err = disks.validate() return @@ -346,6 +359,22 @@ func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { return &generalizedStorage } +// converts to qemuDiskMark +func (storage *QemuScsiStorage) convertDataStructureMark() *qemuDiskMark { + if storage == nil { + return nil + } + if storage.Disk != nil { + return &qemuDiskMark{ + Format: storage.Disk.Format, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + Type: ide, + } + } + return nil +} + // TODO write test func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index e6d9188a..c691e72a 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -566,3 +566,155 @@ func Test_qemuDiskShort_Validate(t *testing.T) { }) } } + +func Test_QemuStorages_markDiskChanges(t *testing.T) { + format_Raw := QemuDiskFormat_Raw + tests := []struct { + name string + storages QemuStorages + currentStorages QemuStorages + output *qemuUpdateChanges + }{ + {name: "Disk CHANGE", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: format_Raw, Size: 100, Storage: "NewStorage"}}}, + Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Format: format_Raw, Size: 50, Storage: "NewStorage"}}}, + Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: format_Raw, Size: 33, Storage: "NewStorage"}}}, + VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: format_Raw, Size: 99, Storage: "NewStorage"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{ + Move: []qemuDiskShort{ + {Format: &format_Raw, Id: "ide0", Storage: "NewStorage"}, + {Format: &format_Raw, Id: "sata1", Storage: "NewStorage"}, + {Format: &format_Raw, Id: "scsi2", Storage: "NewStorage"}, + {Format: &format_Raw, Id: "virtio3", Storage: "NewStorage"}, + }, + Resize: []qemuDiskResize{ + {Id: "ide0", SizeInGigaBytes: 100}, + {Id: "sata1", SizeInGigaBytes: 50}, + {Id: "scsi2", SizeInGigaBytes: 33}, + {Id: "virtio3", SizeInGigaBytes: 99}, + }, + }, + }, + {name: "Disk NO CHANGE", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: format_Raw, Size: 100, Storage: "NewStorage"}}}, + Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Format: format_Raw, Size: 50, Storage: "NewStorage"}}}, + Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: format_Raw, Size: 33, Storage: "NewStorage"}}}, + VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: format_Raw, Size: 99, Storage: "NewStorage"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{}, + }, + {name: "Disk_X.Disk SAME", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{}, + }, + {name: "Disk_X.Disk.Format CHANGE", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{Move: []qemuDiskShort{ + {Format: &format_Raw, Id: "ide2", Storage: "Test"}, + {Format: &format_Raw, Id: "sata3", Storage: "Test"}, + {Format: &format_Raw, Id: "scsi4", Storage: "Test"}, + {Format: &format_Raw, Id: "virtio5", Storage: "Test"}, + }}, + }, + {name: "Disk.Size BIGGER", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 90, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 80, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 50, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 33, Storage: "Test"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{Resize: []qemuDiskResize{ + {Id: "ide3", SizeInGigaBytes: 90}, + {Id: "sata4", SizeInGigaBytes: 80}, + {Id: "scsi5", SizeInGigaBytes: 50}, + {Id: "virtio6", SizeInGigaBytes: 33}, + }}, + }, + {name: "Disk.Size SMALLER", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 1, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 10, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 20, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 31, Storage: "Test"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{}, + }, + {name: "Disk.Storage CHANGE", + storages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "NewStorage"}}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "NewStorage"}}}, + Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "NewStorage"}}}, + VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "NewStorage"}}}, + }, + currentStorages: QemuStorages{ + Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, + }, + output: &qemuUpdateChanges{Move: []qemuDiskShort{ + {Id: "ide1", Storage: "NewStorage"}, + {Id: "sata0", Storage: "NewStorage"}, + {Id: "scsi7", Storage: "NewStorage"}, + {Id: "virtio8", Storage: "NewStorage"}, + }}, + }, + {name: "nil", + output: &qemuUpdateChanges{}, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.output, test.storages.markDiskChanges(test.currentStorages), test.name) + }) + } +} diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index df012dd4..07d8c3a1 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -62,7 +62,7 @@ type QemuVirtIODisks struct { } // TODO write test -func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID uint, params map[string]interface{}, changes *qemuUpdateChanges) { +func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuVirtIODisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -70,8 +70,9 @@ func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - diskMap[i].convertDataStructure().markDiskChanges(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("virtio"+strconv.Itoa(int(i))), params, changes) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("virtio"+strconv.Itoa(int(i))), params, delete) } + return delete } func (disks QemuVirtIODisks) mapToIntMap() map[uint8]*QemuVirtIOStorage { @@ -169,6 +170,18 @@ func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODis return nil } +func (disks QemuVirtIODisks) markDiskChanges(currentDisks *QemuVirtIODisks, changes *qemuUpdateChanges) { + tmpCurrentDisks := QemuVirtIODisks{} + if currentDisks != nil { + tmpCurrentDisks = *currentDisks + } + diskMap := disks.mapToIntMap() + currentDiskMap := tmpCurrentDisks.mapToIntMap() + for i := range diskMap { + diskMap[i].convertDataStructureMark().markChanges(currentDiskMap[i].convertDataStructureMark(), QemuDiskId("virtio"+strconv.Itoa(int(i))), changes) + } +} + func (disks QemuVirtIODisks) Validate() (err error) { _, err = disks.validate() return @@ -252,6 +265,22 @@ func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { return &generalizedStorage } +// converts to qemuDiskMark +func (storage *QemuVirtIOStorage) convertDataStructureMark() *qemuDiskMark { + if storage == nil { + return nil + } + if storage.Disk != nil { + return &qemuDiskMark{ + Format: storage.Disk.Format, + Size: storage.Disk.Size, + Storage: storage.Disk.Storage, + Type: ide, + } + } + return nil +} + // TODO write test func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) From ea32962ede0f3a10f2fbc70c411581d69cb8d3e8 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Sun, 19 Mar 2023 22:51:42 +0000 Subject: [PATCH 095/191] Started on API testing --- .../api/Authentication/authentication_test.go | 38 ++++++++++ test/api/Connection/connection_test.go | 25 +++++++ test/api/Test.go | 58 +++++++++++++++ .../UserManagement/user_management_test.go | 73 +++++++++++++++++++ test/api/preparations.go | 11 +++ 5 files changed, 205 insertions(+) create mode 100644 test/api/Authentication/authentication_test.go create mode 100644 test/api/Connection/connection_test.go create mode 100644 test/api/Test.go create mode 100644 test/api/UserManagement/user_management_test.go create mode 100644 test/api/preparations.go diff --git a/test/api/Authentication/authentication_test.go b/test/api/Authentication/authentication_test.go new file mode 100644 index 00000000..b0a1766f --- /dev/null +++ b/test/api/Authentication/authentication_test.go @@ -0,0 +1,38 @@ +package api_test + +import ( + "github.com/stretchr/testify/require" + "os" + "testing" + "github.com/Telmate/proxmox-api-go/test/api" +) + +func Test_Root_Login_Correct_Password(t *testing.T) { + api_test.SetEnvironmentVariables() + Test := api_test.Test{ + UserID: os.Getenv("PM_USER"), + Password: os.Getenv("PM_PASS"), + } + err := Test.Login() + require.NoError(t, err) +} + +func Test_Root_Login_Incorrect_Password(t *testing.T) { + api_test.SetEnvironmentVariables() + Test := api_test.Test{ + UserID: os.Getenv("PM_USER"), + Password: "xx", + } + err := Test.Login() + require.Error(t, err) +} + +func Test_Login_Incorrect_Username(t *testing.T) { + api_test.SetEnvironmentVariables() + Test := api_test.Test{ + UserID: "xx", + Password: "xx", + } + err := Test.Login() + require.Error(t, err) +} \ No newline at end of file diff --git a/test/api/Connection/connection_test.go b/test/api/Connection/connection_test.go new file mode 100644 index 00000000..8de08811 --- /dev/null +++ b/test/api/Connection/connection_test.go @@ -0,0 +1,25 @@ +package api_test + +import ( + "github.com/stretchr/testify/require" + "testing" + "github.com/Telmate/proxmox-api-go/test/api" +) + +func Test_Connection_Certificate_No_Validation(t *testing.T) { + api_test.SetEnvironmentVariables() + Test := api_test.Test{ + RequireSSL: false, + } + err := Test.CreateTest() + require.NoError(t, err) +} + +func Test_Connection_Certificate_Validation(t *testing.T) { + api_test.SetEnvironmentVariables() + Test := api_test.Test{ + RequireSSL: true, + } + err := Test.CreateTest() + require.Error(t, err) +} \ No newline at end of file diff --git a/test/api/Test.go b/test/api/Test.go new file mode 100644 index 00000000..d1171a5f --- /dev/null +++ b/test/api/Test.go @@ -0,0 +1,58 @@ +package api_test + +import ( + "crypto/tls" + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +type Test struct { + APIurl string + UserID string + Password string + OTP string + HttpHeaders string + RequireSSL bool + + _client *pxapi.Client +} + +func (test *Test) CreateClient() (err error) { + if test.APIurl == "" { + test.APIurl = "https://127.0.0.1:8006/api2/json" + } + if test.UserID == "" { + test.UserID = "root@pam" + } + if test.Password == "" { + test.Password = "root" + } + tlsConfig := &tls.Config{InsecureSkipVerify: true} + + if test.RequireSSL { + tlsConfig = nil + } + + test._client, err = pxapi.NewClient(test.APIurl, nil, test.HttpHeaders, tlsConfig, "", 300) + return err +} + +func (test *Test) GetClient() (client *pxapi.Client) { + return test._client +} + + +func (test *Test) Login() (err error) { + if test._client == nil { + err = test.CreateClient() + if err != nil { + return err + } + } + err = test._client.Login(test.UserID, test.Password, test.OTP) + return err +} + +func (test *Test) CreateTest() (err error) { + err = test.Login() + return err +} diff --git a/test/api/UserManagement/user_management_test.go b/test/api/UserManagement/user_management_test.go new file mode 100644 index 00000000..97694462 --- /dev/null +++ b/test/api/UserManagement/user_management_test.go @@ -0,0 +1,73 @@ +package api_test + +import ( + "github.com/stretchr/testify/require" + "testing" +// "os" + "github.com/Telmate/proxmox-api-go/test/api" + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +var user = pxapi.ConfigUser{ + User: pxapi.UserID{ + Name: "Bob", + Realm: "pve", + }, + Comment: "", + Email: "bob@example.com", + Enable: true, + FirstName: "Bob", + LastName: "Bobson", +} + +func Test_List_Users(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + users, err := pxapi.ListUsers(Test.GetClient(), false) + require.NoError(t, err) + require.Equal(t, 1, len(*users)) +} + +func Test_Create_User(t *testing.T) { + Test := api_test.Test {} + _ = Test.CreateTest() + err := user.CreateUser(Test.GetClient()) + require.NoError(t, err) +} + +func Test_User_Is_Added(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + users, _ := pxapi.ListUsers(Test.GetClient(), false) + var found = false + for _, element := range *users { + if element == user { + found = true + } + } + + require.Equal(t, true, found) +} + +func Test_Remove_User(t *testing.T) { + Test := api_test.Test {} + _ = Test.CreateTest() + err := user.DeleteUser(Test.GetClient()) + require.NoError(t, err) +} + +func Test_User_Is_Removed(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + users, _ := pxapi.ListUsers(Test.GetClient(), false) + var found = false + for _, element := range *users { + if element == user { + found = true + } + } + + require.Equal(t, false, found) +} diff --git a/test/api/preparations.go b/test/api/preparations.go new file mode 100644 index 00000000..0b4f7544 --- /dev/null +++ b/test/api/preparations.go @@ -0,0 +1,11 @@ +package api_test + +import ( + "os" +) + +func SetEnvironmentVariables() { + os.Setenv("PM_API_URL", "https://127.0.0.1:8006/api2/json") + os.Setenv("PM_USER", "root@pam") + os.Setenv("PM_PASS", "root") +} From 4bc42b99820165c0872723d336c5a73dad0af2bc Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Sun, 19 Mar 2023 23:38:36 +0000 Subject: [PATCH 096/191] Acme account testing --- test/api/AcmeAccount/acme_account_test.go | 55 +++++++++++++++++++ .../api/AcmeAccount/list_acme_account_test.go | 14 +++++ 2 files changed, 69 insertions(+) create mode 100644 test/api/AcmeAccount/acme_account_test.go create mode 100644 test/api/AcmeAccount/list_acme_account_test.go diff --git a/test/api/AcmeAccount/acme_account_test.go b/test/api/AcmeAccount/acme_account_test.go new file mode 100644 index 00000000..9c2d8bab --- /dev/null +++ b/test/api/AcmeAccount/acme_account_test.go @@ -0,0 +1,55 @@ +package api_test + +import ( + "github.com/stretchr/testify/require" + "testing" + // "os" + "github.com/Telmate/proxmox-api-go/test/api" + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +var account = ` +{ +"contact": [ +"a@nonexistantdomain.com", +"b@nonexistantdomain.com", +"c@nonexistantdomain.com", +"d@nonexistantdomain.com" +], +"directory": "https://acme-staging-v02.api.letsencrypt.org/directory", +"tos": true +}` + +func Test_Create_Acme_Account(t *testing.T) { + Test := api_test.Test {} + _ = Test.CreateTest() + acmeAccount, _ := pxapi.NewConfigAcmeAccountFromJson([]byte(account)) + err := acmeAccount.CreateAcmeAccount("test", Test.GetClient()) + require.NoError(t, err) +} + +func Test_Acme_Account_Is_Added(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := pxapi.NewConfigAcmeAccountFromApi("test", Test.GetClient()) + + require.NoError(t, err) +} + +func Test_Remove_Acme_Account(t *testing.T) { + Test := api_test.Test {} + _ = Test.CreateTest() + _, err := Test.GetClient().DeleteAcmeAccount("test") + + require.NoError(t, err) +} + +func Test_Acme_Account_Is_Removed(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := pxapi.NewConfigAcmeAccountFromApi("test", Test.GetClient()) + + require.Error(t, err) +} diff --git a/test/api/AcmeAccount/list_acme_account_test.go b/test/api/AcmeAccount/list_acme_account_test.go new file mode 100644 index 00000000..bad0e71a --- /dev/null +++ b/test/api/AcmeAccount/list_acme_account_test.go @@ -0,0 +1,14 @@ +package api_test + +import ( + "github.com/stretchr/testify/require" + "testing" + "github.com/Telmate/proxmox-api-go/test/api" +) + +func Test_List_Acme_Accounts(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + _, err := Test.GetClient().GetAcmeAccountList() + require.NoError(t, err) +} \ No newline at end of file From 42f007ed621bdc00a4ca763603881e6af50753a3 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:58:10 +0000 Subject: [PATCH 097/191] refactor: rename struct --- proxmox/config_qemu_disk.go | 15 +++++++-------- proxmox/config_qemu_disk_test.go | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 118d316e..914f1ffe 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -666,7 +666,7 @@ func (disk *qemuDiskMark) markChanges(currentDisk *qemuDiskMark, id QemuDiskId, if disk.Format != currentDisk.Format { format = &disk.Format } - changes.Move = append(changes.Move, qemuDiskShort{ + changes.Move = append(changes.Move, qemuDiskMove{ Format: format, Id: id, Storage: disk.Storage, @@ -706,14 +706,13 @@ func (disk qemuDiskResize) resize(vmr *VmRef, client *Client) (exitStatus string return client.PutWithTask(map[string]interface{}{"disk": disk.Id, "size": strconv.Itoa(int(disk.SizeInGigaBytes)) + "G"}, fmt.Sprintf("/nodes/%s/%s/%d/resize", vmr.node, vmr.vmType, vmr.vmId)) } -// TODO rename to qemuDiskMove -type qemuDiskShort struct { +type qemuDiskMove struct { Format *QemuDiskFormat Id QemuDiskId Storage string } -func (disk qemuDiskShort) mapToApiValues(delete bool) (params map[string]interface{}) { +func (disk qemuDiskMove) mapToApiValues(delete bool) (params map[string]interface{}) { params = map[string]interface{}{"disk": string(disk.Id), "storage": string(disk.Storage)} if delete { params["delete"] = "1" @@ -724,11 +723,11 @@ func (disk qemuDiskShort) mapToApiValues(delete bool) (params map[string]interfa return } -func (disk qemuDiskShort) move(delete bool, vmr *VmRef, client *Client) (exitStatus interface{}, err error) { +func (disk qemuDiskMove) move(delete bool, vmr *VmRef, client *Client) (exitStatus interface{}, err error) { return client.PostWithTask(disk.mapToApiValues(delete), fmt.Sprintf("/nodes/%s/%s/%d/move_disk", vmr.node, vmr.vmType, vmr.vmId)) } -func (disk qemuDiskShort) Validate() (err error) { +func (disk qemuDiskMove) Validate() (err error) { if disk.Format != nil { err = disk.Format.Validate() if err != nil { @@ -914,7 +913,7 @@ func (storages QemuStorages) Validate() (err error) { } type qemuUpdateChanges struct { - Move []qemuDiskShort + Move []qemuDiskMove Resize []qemuDiskResize } @@ -926,7 +925,7 @@ func diskSubtypeSet(set bool) error { } func MoveQemuDisk(format *QemuDiskFormat, diskId QemuDiskId, storage string, deleteAfterMove bool, vmr *VmRef, client *Client) (err error) { - disk := qemuDiskShort{ + disk := qemuDiskMove{ Format: format, Id: diskId, Storage: storage, diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index c691e72a..1370e50f 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -468,12 +468,12 @@ func Test_qemuDiskShort_mapToApiValues(t *testing.T) { tests := []struct { name string delete bool - input qemuDiskShort + input qemuDiskMove output map[string]interface{} }{ {name: "ALL", delete: true, - input: qemuDiskShort{ + input: qemuDiskMove{ Format: &format_Raw, Id: "ide0", Storage: "test0", @@ -487,7 +487,7 @@ func Test_qemuDiskShort_mapToApiValues(t *testing.T) { }, {name: "Format nil", delete: true, - input: qemuDiskShort{ + input: qemuDiskMove{ Id: "sata4", Storage: "aaa0", }, @@ -498,7 +498,7 @@ func Test_qemuDiskShort_mapToApiValues(t *testing.T) { }, }, {name: "Delete false", - input: qemuDiskShort{ + input: qemuDiskMove{ Format: &format_Qcow2, Id: "scsi10", Storage: "test0", @@ -510,7 +510,7 @@ func Test_qemuDiskShort_mapToApiValues(t *testing.T) { }, }, {name: "MINIMAL", - input: qemuDiskShort{ + input: qemuDiskMove{ Id: "virtio13", Storage: "Test0", }, @@ -533,26 +533,26 @@ func Test_qemuDiskShort_Validate(t *testing.T) { format_Empty := QemuDiskFormat("") tests := []struct { name string - input qemuDiskShort + input qemuDiskMove err error }{ // TODO Add cases when Storage has a custom type // Invalid - {name: "Invalid 00", input: qemuDiskShort{Format: &format_Invalid}, + {name: "Invalid 00", input: qemuDiskMove{Format: &format_Invalid}, err: QemuDiskFormat("").Error(), }, - {name: "Invalid 01", input: qemuDiskShort{Format: &format_Empty}, + {name: "Invalid 01", input: qemuDiskMove{Format: &format_Empty}, err: QemuDiskFormat("").Error(), }, - {name: "Invalid 02", input: qemuDiskShort{Id: "invalid"}, + {name: "Invalid 02", input: qemuDiskMove{Id: "invalid"}, err: errors.New(ERROR_QemuDiskId_Invalid), }, // Valid - {name: "Valid 00", input: qemuDiskShort{ + {name: "Valid 00", input: qemuDiskMove{ Format: &format_Raw, Id: "ide0", }}, - {name: "Valid 01", input: qemuDiskShort{ + {name: "Valid 01", input: qemuDiskMove{ Id: "ide0", }}, } @@ -589,7 +589,7 @@ func Test_QemuStorages_markDiskChanges(t *testing.T) { VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, }, output: &qemuUpdateChanges{ - Move: []qemuDiskShort{ + Move: []qemuDiskMove{ {Format: &format_Raw, Id: "ide0", Storage: "NewStorage"}, {Format: &format_Raw, Id: "sata1", Storage: "NewStorage"}, {Format: &format_Raw, Id: "scsi2", Storage: "NewStorage"}, @@ -646,7 +646,7 @@ func Test_QemuStorages_markDiskChanges(t *testing.T) { Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Vmdk, Size: 32, Storage: "Test"}}}, }, - output: &qemuUpdateChanges{Move: []qemuDiskShort{ + output: &qemuUpdateChanges{Move: []qemuDiskMove{ {Format: &format_Raw, Id: "ide2", Storage: "Test"}, {Format: &format_Raw, Id: "sata3", Storage: "Test"}, {Format: &format_Raw, Id: "scsi4", Storage: "Test"}, @@ -701,7 +701,7 @@ func Test_QemuStorages_markDiskChanges(t *testing.T) { Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Size: 32, Storage: "Test"}}}, }, - output: &qemuUpdateChanges{Move: []qemuDiskShort{ + output: &qemuUpdateChanges{Move: []qemuDiskMove{ {Id: "ide1", Storage: "NewStorage"}, {Id: "sata0", Storage: "NewStorage"}, {Id: "scsi7", Storage: "NewStorage"}, From b168399e0eb92104a263c12a39e2e6d604ae454b Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:07:41 +0000 Subject: [PATCH 098/191] refactor: make `Id` a value that is only returned --- proxmox/config_qemu_disk.go | 7 +- proxmox/config_qemu_disk_ide.go | 2 +- proxmox/config_qemu_disk_sata.go | 2 +- proxmox/config_qemu_disk_scsi.go | 2 +- proxmox/config_qemu_disk_virtio.go | 2 +- proxmox/config_qemu_test.go | 150 ++++++++++++++--------------- 6 files changed, 82 insertions(+), 83 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 914f1ffe..973fcc03 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -188,7 +188,7 @@ type qemuDisk struct { // TODO custom type File string // Only set for Passthrough. Format QemuDiskFormat // Only set for Disk - Id *uint // Only set for Disk + Id uint // Only set for Disk IOThread bool // Only set for scsi,virtio Number uint ReadOnly bool // Only set for scsi,virtio @@ -215,7 +215,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { } else { // test:100/vm-100-disk-0.raw tmpId := strconv.Itoa(int(vmID)) - settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(*disk.Id)) + "." + string(disk.Format) + settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(disk.Id)) + "." + string(disk.Format) } } @@ -308,8 +308,7 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { tmp := strings.Split(idAndFormat[0], "-") if len(tmp) > 1 { tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) - idPointer := uint(tmpId) - disk.Id = &idPointer + disk.Id = uint(tmpId) } } } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index d6d641b9..9940d8d5 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -10,7 +10,7 @@ type QemuIdeDisk struct { Discard bool `json:"discard"` EmulateSSD bool `json:"emulatessd"` Format QemuDiskFormat `json:"format"` - Id *uint `json:"id,omitempty"` + Id uint `json:"id"` //Id is only returned and setting it has no effect Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size"` diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index b45570c9..fd69d071 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -10,7 +10,7 @@ type QemuSataDisk struct { Discard bool `json:"discard"` EmulateSSD bool `json:"emulatessd"` Format QemuDiskFormat `json:"format"` - Id *uint `json:"id,omitempty"` + Id uint `json:"id"` //Id is only returned and setting it has no effect Replicate bool `json:"replicate"` Serial QemuDiskSerial `json:"serial,omitempty"` Size uint `json:"size"` diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index c9407e2f..80f31712 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -10,7 +10,7 @@ type QemuScsiDisk struct { Discard bool `json:"discard"` EmulateSSD bool `json:"emulatessd"` Format QemuDiskFormat `json:"format"` - Id *uint `json:"id,omitempty"` + Id uint `json:"id"` //Id is only returned and setting it has no effect IOThread bool `json:"iothread"` ReadOnly bool `json:"readonly"` Replicate bool `json:"replicate"` diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 07d8c3a1..a7f2390d 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -9,7 +9,7 @@ type QemuVirtIODisk struct { Cache QemuDiskCache `json:"cache,omitempty"` Discard bool `json:"discard"` Format QemuDiskFormat `json:"format"` - Id *uint `json:"id,omitempty"` + Id uint `json:"id"` //Id is only returned and setting it has no effect IOThread bool `json:"iothread"` ReadOnly bool `json:"readonly"` Replicate bool `json:"replicate"` diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 3e73d1a4..8612d5d7 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -52,7 +52,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -76,7 +76,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Discard: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: false, Serial: "disk-9763", Size: 1032, @@ -89,7 +89,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -99,7 +99,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: false, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -110,7 +110,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Cache: QemuDiskCache_WriteThrough, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -121,7 +121,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Discard: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -132,7 +132,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 12}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -143,7 +143,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -154,7 +154,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 15}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -165,7 +165,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -176,7 +176,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.46}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -187,7 +187,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -198,7 +198,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.68}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -209,7 +209,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -219,7 +219,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: false, Storage: "test2", }}}}}, @@ -229,7 +229,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Serial: "disk-9763", Storage: "test2", @@ -240,7 +240,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Size: 1032, Storage: "test2", @@ -252,7 +252,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint53, + Id: uint53, Replicate: true, Storage: "test2", }}}}}, @@ -463,7 +463,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -487,7 +487,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Discard: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: false, Serial: "disk-9763", Size: 32, @@ -500,7 +500,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -510,7 +510,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: false, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -521,7 +521,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Cache: QemuDiskCache_None, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -532,7 +532,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Discard: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -543,7 +543,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -554,7 +554,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -565,7 +565,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -576,7 +576,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -587,7 +587,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -598,7 +598,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -613,7 +613,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, }, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -624,7 +624,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -634,7 +634,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: false, Storage: "test2", }}}}}, @@ -644,7 +644,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Serial: "disk-9763", Storage: "test2", @@ -655,7 +655,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Size: 32, Storage: "test2", @@ -667,7 +667,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint47, + Id: uint47, Replicate: true, Storage: "test2", }}}}}, @@ -878,7 +878,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -902,7 +902,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Discard: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, IOThread: true, ReadOnly: true, Replicate: false, @@ -917,7 +917,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -927,7 +927,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: false, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -938,7 +938,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Cache: QemuDiskCache_WriteBack, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -949,7 +949,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Discard: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -960,7 +960,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -971,7 +971,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -982,7 +982,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -993,7 +993,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1003,7 +1003,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, IOThread: true, Replicate: true, Storage: "test", @@ -1015,7 +1015,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1026,7 +1026,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1037,7 +1037,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1048,7 +1048,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1058,7 +1058,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: false, Storage: "test", }}}}}, @@ -1068,7 +1068,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, ReadOnly: true, Replicate: true, Storage: "test", @@ -1079,7 +1079,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Serial: "disk-9763", Storage: "test", @@ -1090,7 +1090,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Size: 32, Storage: "test", @@ -1102,7 +1102,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, EmulateSSD: true, Format: QemuDiskFormat_Qcow2, - Id: &uint2, + Id: uint2, Replicate: true, Storage: "test", }}}}}, @@ -1333,7 +1333,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1356,7 +1356,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Cache: QemuDiskCache_DirectSync, Discard: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, IOThread: true, ReadOnly: true, Replicate: false, @@ -1371,7 +1371,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1381,7 +1381,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: false, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1392,7 +1392,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Cache: QemuDiskCache_DirectSync, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1403,7 +1403,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Discard: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1414,7 +1414,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1429,7 +1429,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, }, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1440,7 +1440,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 11}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1451,7 +1451,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1461,7 +1461,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, IOThread: true, Replicate: true, Storage: "test2", @@ -1477,7 +1477,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, }, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1488,7 +1488,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1499,7 +1499,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1510,7 +1510,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Storage: "test2", }}}}}, @@ -1520,7 +1520,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: false, Storage: "test2", }}}}}, @@ -1530,7 +1530,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, ReadOnly: true, Replicate: true, Storage: "test2", @@ -1541,7 +1541,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Serial: "disk-9763", Storage: "test2", @@ -1552,7 +1552,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Format: QemuDiskFormat_Qcow2, - Id: &uint31, + Id: uint31, Replicate: true, Size: 32, Storage: "test2", From c04f9e31e884dc36e199fb3ef43cbfc5bbfd7062 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:51:51 +0000 Subject: [PATCH 099/191] test: add test add test for `ConfigQemu{}.mapToApiValues` --- proxmox/config_qemu_test.go | 1791 +++++++++++++++++++++++++++++++++++ 1 file changed, 1791 insertions(+) diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 8612d5d7..31034762 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -9,6 +9,1797 @@ import ( "github.com/stretchr/testify/require" ) +func Test_ConfigQemu_mapToApiValues(t *testing.T) { + format_Raw := QemuDiskFormat_Raw + float10 := float32(10.3) + float45 := float32(45.23) + float79 := float32(79.23) + float99 := float32(99.2) + uint23 := uint(23) + uint34 := uint(34) + uint78 := uint(78) + uint89 := uint(89) + update_CloudInit := &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "test"} + ideBase := &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} + sataBase := &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} + scsiBase := &QemuScsiStorage{Disk: &QemuScsiDisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} + virtioBase := &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} + tests := []struct { + name string + config *ConfigQemu + currentConfig ConfigQemu + vmr *VmRef + output map[string]interface{} + }{ + // Create Disks + + // Create Disks.Ide + {name: "Create Disks.Ide.Disk_X.CdRom none", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"ide0": "none,media=cdrom"}, + }, + {name: "Create Disks.Ide.Disk_X.CdRom.Iso", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"ide1": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Create Disks.Ide.Disk_X.CdRom.Passthrough", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"ide2": "cdrom,media=cdrom"}, + }, + {name: "Create Disks.Ide.Disk_X.CloudInit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + output: map[string]interface{}{"ide1": "Test:cloudinit,format=raw"}, + }, + // Create Disks.Ide.Disk_X.Disk + {name: "Create Disks.Ide.Disk_X.Disk All", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + Format: format_Raw, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + }}}}}, + output: map[string]interface{}{"ide0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=558485ef-478,ssd=1"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, + output: map[string]interface{}{"ide1": ",aio=native,backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Backup: true}}}}}, + output: map[string]interface{}{"ide2": ",replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Cache: QemuDiskCache_DirectSync}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,cache=directsync,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Discard: true}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{EmulateSSD: true}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Format", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Format: format_Raw}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,format=raw,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Replicate: true}}}}}, + output: map[string]interface{}{"ide1": ",backup=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Serial: "558485ef-478"}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,replicate=0,serial=558485ef-478"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Size", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Size: 32}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Storage", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Storage: "Test"}}}}}, + output: map[string]interface{}{"ide0": "Test:0,backup=0,replicate=0"}, + }, + // Create Disks.Ide.Disk_X.Passthrough + {name: "Create Disks.Ide.Disk_X.Passthrough All", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "test-serial_757465-gdg", + }}}}}, + output: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, + output: map[string]interface{}{"ide1": ",aio=threads,backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Backup: true}}}}}, + output: map[string]interface{}{"ide2": ",replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Cache: QemuDiskCache_Unsafe}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,cache=unsafe,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Discard: true}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{EmulateSSD: true}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.File", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}}}}}, + output: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.replicate", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Replicate: true}}}}}, + output: map[string]interface{}{"ide2": ",backup=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Serial: "test-serial_757465-gdg"}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, + }, + // Create Disks.Sata + {name: "Create Disks.Sata.Disk_X.Disk_X.CdRom none", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"sata0": "none,media=cdrom"}, + }, + {name: "Create Disks.Sata.Disk_X.CdRom.Iso", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"sata1": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Create Disks.Sata.Disk_X.CdRom.Passthrough", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"sata2": "cdrom,media=cdrom"}, + }, + {name: "Create Disks.Sata.Disk_X.CloudInit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + output: map[string]interface{}{"sata1": "Test:cloudinit,format=raw"}, + }, + // Create Disks.Sata.Disk_X.Disk + {name: "Create Disks.Sata.Disk_X.Disk ALL", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Replicate: true, + Serial: "ab_C-12_3", + Size: 32, + Storage: "Test", + }}}}}, + output: map[string]interface{}{"sata0": "Test:32,aio=native,cache=unsafe,discard=on,format=qcow2,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=ab_C-12_3,ssd=1"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, + output: map[string]interface{}{"sata0": ",aio=native,backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Backup: true}}}}}, + output: map[string]interface{}{"sata1": ",replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Cache: QemuDiskCache_DirectSync}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,cache=directsync,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Discard: true}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{EmulateSSD: true}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Format", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Format: format_Raw}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,format=raw,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Replicate: true}}}}}, + output: map[string]interface{}{"sata2": ",backup=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Serial: "558485ef-478"}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,replicate=0,serial=558485ef-478"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Size", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Size: 32}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Storage", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Storage: "Test"}}}}}, + output: map[string]interface{}{"sata5": "Test:0,backup=0,replicate=0"}, + }, + // Create Disks.Sata.Disk_X.Passthrough + {name: "Create Disks.Sata.Disk_X.Passthrough All", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "test-serial_757465-gdg", + }}}}}, + output: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, + output: map[string]interface{}{"sata1": ",aio=threads,backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Backup: true}}}}}, + output: map[string]interface{}{"sata2": ",replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,cache=unsafe,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Discard: true}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{EmulateSSD: true}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.File", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}}}}}, + output: map[string]interface{}{"sata3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Replicate: true}}}}}, + output: map[string]interface{}{"sata4": ",backup=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Serial: "test-serial_757465-gdg"}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, + }, + // Create Disks.Scsi + {name: "Create Disks.Scsi.CdRom none", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"scsi0": "none,media=cdrom"}, + }, + {name: "Create Disks.Scsi.CdRom.Iso", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"scsi1": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Create Disks.Scsi.CdRom.Passthrough", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"scsi2": "cdrom,media=cdrom"}, + }, + {name: "Create Disks.Scsi.CloudInit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + output: map[string]interface{}{"scsi1": "Test:cloudinit,format=raw"}, + }, + // Create Disks.Scsi.Disk_X.Disk + {name: "Create Disks.Scsi.Disk_X.Disk All", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + Format: format_Raw, + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + }}}}}, + output: map[string]interface{}{"scsi0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,ssd=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, + output: map[string]interface{}{"scsi1": ",aio=native,backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Backup: true}}}}}, + output: map[string]interface{}{"scsi2": ",replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"scsi3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi11": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi12": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"scsi14": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi15": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{Cache: QemuDiskCache_DirectSync}}}}}, + output: map[string]interface{}{"scsi18": ",backup=0,cache=directsync,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{Discard: true}}}}}, + output: map[string]interface{}{"scsi19": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: &QemuScsiStorage{Disk: &QemuScsiDisk{EmulateSSD: true}}}}}, + output: map[string]interface{}{"scsi20": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Format", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: &QemuScsiStorage{Disk: &QemuScsiDisk{Format: format_Raw}}}}}, + output: map[string]interface{}{"scsi20": ",backup=0,format=raw,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.IOThread", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{IOThread: true}}}}}, + output: map[string]interface{}{"scsi21": ",backup=0,iothread=1,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.ReadOnly", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_22: &QemuScsiStorage{Disk: &QemuScsiDisk{ReadOnly: true}}}}}, + output: map[string]interface{}{"scsi22": ",backup=0,replicate=0,ro=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_23: &QemuScsiStorage{Disk: &QemuScsiDisk{Replicate: true}}}}}, + output: map[string]interface{}{"scsi23": ",backup=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_24: &QemuScsiStorage{Disk: &QemuScsiDisk{Serial: "558485ef-478"}}}}}, + output: map[string]interface{}{"scsi24": ",backup=0,replicate=0,serial=558485ef-478"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Size", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_25: &QemuScsiStorage{Disk: &QemuScsiDisk{Size: 32}}}}}, + output: map[string]interface{}{"scsi25": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Storage", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_26: &QemuScsiStorage{Disk: &QemuScsiDisk{Storage: "Test"}}}}}, + output: map[string]interface{}{"scsi26": "Test:0,backup=0,replicate=0"}, + }, + // Create Disks.Scsi.Passthrough + {name: "Create Disks.Scsi.Disk_X.Passthrough All", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "test-serial_757465-gdg", + }}}}}, + output: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,ssd=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, + output: map[string]interface{}{"scsi1": ",aio=threads,backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Backup", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Backup: true}}}}}, + output: map[string]interface{}{"scsi2": ",replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"scsi3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"scsi11": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi12": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"scsi14": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi15": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Cache", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, + output: map[string]interface{}{"scsi18": ",backup=0,cache=unsafe,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Discard", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Discard: true}}}}}, + output: map[string]interface{}{"scsi19": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.EmulateSSD", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{EmulateSSD: true}}}}}, + output: map[string]interface{}{"scsi20": ",backup=0,replicate=0,ssd=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.File", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}}}}}, + output: map[string]interface{}{"scsi21": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.IOThread", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_22: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{IOThread: true}}}}}, + output: map[string]interface{}{"scsi22": ",backup=0,iothread=1,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.ReadOnly", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_23: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ReadOnly: true}}}}}, + output: map[string]interface{}{"scsi23": ",backup=0,replicate=0,ro=1"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_24: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Replicate: true}}}}}, + output: map[string]interface{}{"scsi24": ",backup=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Serial", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_25: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Serial: "test-serial_757465-gdg"}}}}}, + output: map[string]interface{}{"scsi25": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, + }, + // Create Disks.VirtIO + {name: "Create Disks.VirtIO.Disk_X.CdRom none", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"virtio0": "none,media=cdrom"}, + }, + {name: "Create Disks.VirtIO.Disk_X.CdRom.Iso", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"virtio1": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Create Disks.VirtIO.Disk_X.CdRom.Passthrough", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"virtio2": "cdrom,media=cdrom"}, + }, + {name: "Create Disks.VirtIO.Disk_X.CloudInit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + output: map[string]interface{}{"virtio1": "Test:cloudinit,format=raw"}, + }, + // Create Disks.VirtIO.Disk + {name: "Create Disks.VirtIO.Disk_X.Disk All", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: format_Raw, + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + }}}}}, + output: map[string]interface{}{"virtio0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, + output: map[string]interface{}{"virtio1": ",aio=native,backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Backup", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Backup: true}}}}}, + output: map[string]interface{}{"virtio2": ",replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"virtio3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"virtio10": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"virtio11": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio12": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"virtio14": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio15": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Cache", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Cache: QemuDiskCache_DirectSync}}}}}, + output: map[string]interface{}{"virtio2": ",backup=0,cache=directsync,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Discard", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Discard: true}}}}}, + output: map[string]interface{}{"virtio3": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Format", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Format: format_Raw}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,format=raw,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.IOThread", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{IOThread: true}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,iothread=1,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.ReadOnly", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ReadOnly: true}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,replicate=0,ro=1"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Replicate: true}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Serial", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Serial: "558485ef-478"}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,replicate=0,serial=558485ef-478"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Size", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Size: 32}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Storage", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Storage: "Test"}}}}}, + output: map[string]interface{}{"virtio9": "Test:0,backup=0,replicate=0"}, + }, + // Create Disks.VirtIO.Disk_X.Passthrough + {name: "Create Disks.VirtIO.Disk_X.Passthrough All", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: true, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, + WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, + WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + }, + }, + Cache: QemuDiskCache_Unsafe, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "test-serial_757465-gdg", + }}}}}, + output: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.AsyncIO", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, + output: map[string]interface{}{"virtio1": ",aio=threads,backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Backup", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Backup: true}}}}}, + output: map[string]interface{}{"virtio2": ",replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, + output: map[string]interface{}{"virtio3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"virtio10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"virtio11": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio12": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"virtio14": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio15": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Cache", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, + output: map[string]interface{}{"virtio2": ",backup=0,cache=unsafe,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Discard", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Discard: true}}}}}, + output: map[string]interface{}{"virtio3": ",backup=0,discard=on,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.File", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}}}}}, + output: map[string]interface{}{"virtio4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.IOThread", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{IOThread: true}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,iothread=1,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.ReadOnly", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ReadOnly: true}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,replicate=0,ro=1"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Replicate", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Replicate: true}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Serial", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Serial: "test-serial_757465-gdg"}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, + }, + // Create Iso + {name: "Create Iso", + config: &ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + output: map[string]interface{}{"ide2": "test:iso/file.iso,media=cdrom"}, + }, + // Update + + // Update Disk.Ide + {name: "Update Disk.Ide.Disk_X DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{}}}}, + output: map[string]interface{}{"delete": "ide0"}, + }, + // Update Disk.Ide.Disk_X.CdRom + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE ISO TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"ide1": "none,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE ISO TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"ide2": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE None TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"ide3": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE None TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"ide0": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE Passthrough TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"ide1": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom CHANGE Passthrough TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"ide2": "none,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{}}}}, + output: map[string]interface{}{"delete": "ide3"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"ide0": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom.Iso.File CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test2.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"ide1": "Test:iso/test2.iso,media=cdrom"}, + }, + {name: "Update Disk.Ide.Disk_X.CdRom.Iso.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "NewStorage"}}}}}}, + output: map[string]interface{}{"ide2": "NewStorage:iso/test.iso,media=cdrom"}, + }, + // Update Disk.Ide.Disk_X.CloudInit + {name: "Update Disk.Ide.Disk_X.CloudInit DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{}}}}, + output: map[string]interface{}{"delete": "ide3"}, + }, + {name: "Update Disk.Ide.Disk_X.CloudInit SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: update_CloudInit}}}}, + output: map[string]interface{}{"ide0": "test:cloudinit,format=raw"}, + }, + {name: "Update Disk.Ide.Disk_X.CloudInit.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Qcow2, Storage: "Test"}}}}}, + output: map[string]interface{}{"ide1": "Test:cloudinit,format=qcow2"}, + }, + {name: "Update Disk.Ide.Disk_X.CloudInit.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "NewStorage"}}}}}, + output: map[string]interface{}{"ide2": "NewStorage:cloudinit,format=raw"}, + }, + // Update Disk.Ide.Disk_X.Disk + {name: "Update Disk.Ide.Disk_X.Disk CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{}}}}, + output: map[string]interface{}{"delete": "ide0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk MIGRATE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"ide1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk RESIZE DOWN", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide2": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk RESIZE UP", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, + output: map[string]interface{}{"ide0": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Qcow2, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide1": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + // Update Disk.Sata + {name: "Update Disk.Sata.Disk_X DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{}}}}, + output: map[string]interface{}{"delete": "sata0"}, + }, + // Update Disk.Sata.Disk_X.CdRom + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE ISO TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"sata1": "none,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE ISO TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"sata2": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE None TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"sata3": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE None TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"sata4": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE Passthrough TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"sata5": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom CHANGE Passthrough TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"sata0": "none,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{}}}}, + output: map[string]interface{}{"delete": "sata1"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"sata2": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom.Iso.File CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test2.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"sata3": "Test:iso/test2.iso,media=cdrom"}, + }, + {name: "Update Disk.Sata.Disk_X.CdRom.Iso.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "NewStorage"}}}}}}, + output: map[string]interface{}{"sata4": "NewStorage:iso/test.iso,media=cdrom"}, + }, + // Update Disk.Sata.Disk_X.CloudInit + {name: "Update Disk.Sata.Disk_X.CloudInit DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{}}}}, + output: map[string]interface{}{"delete": "sata5"}, + }, + {name: "Update Disk.Sata.Disk_X.CloudInit SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: update_CloudInit}}}}, + output: map[string]interface{}{"sata0": "test:cloudinit,format=raw"}, + }, + {name: "Update Disk.Sata.Disk_X.CloudInit.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Qcow2, Storage: "Test"}}}}}, + output: map[string]interface{}{"sata1": "Test:cloudinit,format=qcow2"}, + }, + {name: "Update Disk.Sata.Disk_X.CloudInit.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "NewStorage"}}}}}, + output: map[string]interface{}{"sata2": "NewStorage:cloudinit,format=raw"}, + }, + // Update Disk.Sata.Disk_X.Disk + {name: "Update Disk.Sata.Disk_X.Disk CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: sataBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{}}}}, + output: map[string]interface{}{"delete": "sata4"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk MIGRATE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"sata5": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk RESIZE DOWN", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata0": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk RESIZE UP", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata1": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: sataBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: sataBase}}}, + output: map[string]interface{}{"sata2": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Qcow2, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + // Update Disk.Scsi + {name: "Update Disk.Scsi.Disk_X DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{}}}}, + output: map[string]interface{}{"delete": "scsi0"}, + }, + // Update Disk.Scsi.Disk_X.CdRom + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE ISO TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"scsi1": "none,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE ISO TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"scsi2": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE None TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"scsi3": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE None TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"scsi4": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE Passthrough TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"scsi5": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom CHANGE Passthrough TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"scsi6": "none,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{}}}}, + output: map[string]interface{}{"delete": "scsi7"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"scsi8": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom.Iso.File CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test2.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"scsi9": "Test:iso/test2.iso,media=cdrom"}, + }, + {name: "Update Disk.Scsi.Disk_X.CdRom.Iso.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "NewStorage"}}}}}}, + output: map[string]interface{}{"scsi10": "NewStorage:iso/test.iso,media=cdrom"}, + }, + // Update Disk.Scsi.Disk_X.CloudInit + {name: "Update Disk.Scsi.Disk_X.CloudInit DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{}}}}, + output: map[string]interface{}{"delete": "scsi11"}, + }, + {name: "Update Disk.Scsi.Disk_X.CloudInit SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{CloudInit: update_CloudInit}}}}, + output: map[string]interface{}{"scsi12": "test:cloudinit,format=raw"}, + }, + {name: "Update Disk.Scsi.Disk_X.CloudInit.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Qcow2, Storage: "Test"}}}}}, + output: map[string]interface{}{"scsi13": "Test:cloudinit,format=qcow2"}, + }, + {name: "Update Disk.Scsi.Disk_X.CloudInit.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "NewStorage"}}}}}, + output: map[string]interface{}{"scsi14": "NewStorage:cloudinit,format=raw"}, + }, + // Update Disk.Scsi.Disk_X.Disk + {name: "Update Disk.Scsi.Disk_X.Disk CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: scsiBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{}}}}, + output: map[string]interface{}{"delete": "scsi16"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk MIGRATE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"scsi17": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk RESIZE DOWN", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi18": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk RESIZE UP", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi19": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: scsiBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: scsiBase}}}, + output: map[string]interface{}{"scsi20": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Qcow2, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi21": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + // Update Disk.VirtIO + {name: "Update Disk.VirtIO.Disk_X DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}}}, + output: map[string]interface{}{"delete": "virtio0"}, + }, + // Update Disk.VirtIO.Disk_X.CdRom + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE ISO TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"virtio1": "none,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE ISO TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"virtio2": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE None TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"virtio3": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE None TO Passthrough", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"virtio4": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE Passthrough TO ISO", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"virtio5": "Test:iso/test.iso,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom CHANGE Passthrough TO None", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, + output: map[string]interface{}{"virtio6": "none,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{}}}}, + output: map[string]interface{}{"delete": "virtio7"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, + output: map[string]interface{}{"virtio8": "cdrom,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom.Iso.File CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test2.iso", Storage: "Test"}}}}}}, + output: map[string]interface{}{"virtio9": "Test:iso/test2.iso,media=cdrom"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CdRom.Iso.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "NewStorage"}}}}}}, + output: map[string]interface{}{"virtio10": "NewStorage:iso/test.iso,media=cdrom"}, + }, + // Update Disk.VirtIO.Disk_X.CloudInit + {name: "Update Disk.VirtIO.Disk_X.CloudInit DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{}}}}, + output: map[string]interface{}{"delete": "virtio11"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CloudInit SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{CloudInit: update_CloudInit}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{CloudInit: update_CloudInit}}}}, + output: map[string]interface{}{"virtio12": "test:cloudinit,format=raw"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CloudInit.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: QemuDiskFormat_Qcow2, Storage: "Test"}}}}}, + output: map[string]interface{}{"virtio13": "Test:cloudinit,format=qcow2"}, + }, + {name: "Update Disk.VirtIO.Disk_X.CloudInit.Storage CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "NewStorage"}}}}}, + output: map[string]interface{}{"virtio14": "NewStorage:cloudinit,format=raw"}, + }, + // Update Disk.VirtIO.Disk_X.Disk + {name: "Update Disk.VirtIO.Disk_X.Disk CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk DELETE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: virtioBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}}}, + output: map[string]interface{}{"delete": "virtio0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk MIGRATE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"virtio1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE DOWN", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio2": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE UP", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: virtioBase}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: virtioBase}}}, + output: map[string]interface{}{"virtio4": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk.Format CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Qcow2, + Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio5": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + // Update Iso + {name: "Update Iso nil", + currentConfig: ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + config: &ConfigQemu{Iso: nil}, + output: map[string]interface{}{}, + }, + {name: "Update Iso SAME", + currentConfig: ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + config: &ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + output: map[string]interface{}{"ide2": "test:iso/file.iso,media=cdrom"}, + }, + {name: "Update Iso.File", + currentConfig: ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + config: &ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file2.iso"}}, + output: map[string]interface{}{"ide2": "test:iso/file2.iso,media=cdrom"}, + }, + {name: "Update Iso.Storage", + currentConfig: ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, + config: &ConfigQemu{Iso: &IsoFile{Storage: "NewStorage", File: "file.iso"}}, + output: map[string]interface{}{"ide2": "NewStorage:iso/file.iso,media=cdrom"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + tmpParams, _ := test.config.mapToApiValues(test.currentConfig) + require.Equal(t, test.output, tmpParams, test.name) + }) + } +} + func Test_ConfigQemu_mapToStruct(t *testing.T) { uint2 := uint(2) uint31 := uint(31) From 75c1484dbc79bad4e755dd452d4dd1a35237144d Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:57:49 +0000 Subject: [PATCH 100/191] test: remove TODO test cases have been covered indirectly --- proxmox/config_qemu_disk.go | 4 ---- proxmox/config_qemu_disk_ide.go | 4 ---- proxmox/config_qemu_disk_sata.go | 4 ---- proxmox/config_qemu_disk_scsi.go | 4 ---- proxmox/config_qemu_disk_virtio.go | 4 ---- 5 files changed, 20 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 973fcc03..d2691913 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -41,7 +41,6 @@ const ( Error_QemuCdRom_MutuallyExclusive string = "iso and passthrough are mutually exclusive" ) -// TODO write test func (cdRom QemuCdRom) mapToApiValues() string { if cdRom.Passthrough { return "cdrom,media=cdrom" @@ -155,7 +154,6 @@ func (QemuCloudInitDisk) checkDuplicates(numberOFCloudInitDrives uint8) error { return nil } -// TODO write test func (cloudInit QemuCloudInitDisk) mapToApiValues() string { return cloudInit.Storage + ":cloudinit,format=" + string(cloudInit.Format) } @@ -207,7 +205,6 @@ const ( Error_QemuDisk_Storage string = "storage may not be empty" ) -// TODO write test func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { if disk.Storage != "" { if create { @@ -288,7 +285,6 @@ func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { } // Maps all the disk related settings -// TODO write test func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(settings) == 0 { return nil diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 9940d8d5..8149eada 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -47,7 +47,6 @@ type QemuIdeDisks struct { Disk_3 *QemuIdeStorage `json:"3,omitempty"` } -// TODO write test func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuIdeDisks{} if currentDisks != nil { @@ -70,7 +69,6 @@ func (disks QemuIdeDisks) mapToIntMap() map[uint8]*QemuIdeStorage { } } -// TODO write test func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { disks := QemuIdeDisks{} var structPopulated bool @@ -170,7 +168,6 @@ type QemuIdeStorage struct { Passthrough *QemuIdePassthrough `json:"passthrough,omitempty"` } -// TODO write test // converts to qemuStorage func (storage *QemuIdeStorage) convertDataStructure() *qemuStorage { if storage == nil { @@ -205,7 +202,6 @@ func (storage *QemuIdeStorage) convertDataStructureMark() *qemuDiskMark { return nil } -// TODO write test func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index fd69d071..6ca552b8 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -49,7 +49,6 @@ type QemuSataDisks struct { Disk_5 *QemuSataStorage `json:"5,omitempty"` } -// TODO write test func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuSataDisks{} if currentDisks != nil { @@ -74,7 +73,6 @@ func (disks QemuSataDisks) mapToIntMap() map[uint8]*QemuSataStorage { } } -// TODO write test func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { disks := QemuSataDisks{} var structPopulated bool @@ -182,7 +180,6 @@ type QemuSataStorage struct { Passthrough *QemuSataPassthrough `json:"passthrough,omitempty"` } -// TODO write test // converts to qemuStorage func (storage *QemuSataStorage) convertDataStructure() *qemuStorage { if storage == nil { @@ -217,7 +214,6 @@ func (storage *QemuSataStorage) convertDataStructureMark() *qemuDiskMark { return nil } -// TODO write test func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 80f31712..483ab68b 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -78,7 +78,6 @@ type QemuScsiDisks struct { Disk_30 *QemuScsiStorage `json:"30,omitempty"` } -// TODO write test func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuScsiDisks{} if currentDisks != nil { @@ -128,7 +127,6 @@ func (disks QemuScsiDisks) mapToIntMap() map[uint8]*QemuScsiStorage { } } -// TODO write test func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { disks := QemuScsiDisks{} var structPopulated bool @@ -340,7 +338,6 @@ type QemuScsiStorage struct { Passthrough *QemuScsiPassthrough `json:"passthrough,omitempty"` } -// TODO write test // converts to qemuStorage func (storage *QemuScsiStorage) convertDataStructure() *qemuStorage { if storage == nil { @@ -375,7 +372,6 @@ func (storage *QemuScsiStorage) convertDataStructureMark() *qemuDiskMark { return nil } -// TODO write test func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index a7f2390d..a55f45b9 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -61,7 +61,6 @@ type QemuVirtIODisks struct { Disk_15 *QemuVirtIOStorage `json:"15,omitempty"` } -// TODO write test func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuVirtIODisks{} if currentDisks != nil { @@ -96,7 +95,6 @@ func (disks QemuVirtIODisks) mapToIntMap() map[uint8]*QemuVirtIOStorage { } } -// TODO write test func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODisks { disks := QemuVirtIODisks{} var structPopulated bool @@ -246,7 +244,6 @@ type QemuVirtIOStorage struct { Passthrough *QemuVirtIOPassthrough `json:"passthrough,omitempty"` } -// TODO write test // converts to qemuStorage func (storage *QemuVirtIOStorage) convertDataStructure() *qemuStorage { if storage == nil { @@ -281,7 +278,6 @@ func (storage *QemuVirtIOStorage) convertDataStructureMark() *qemuDiskMark { return nil } -// TODO write test func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) From 8ece1697f582625d8b6f9b5fe5e98cdcafb5a242 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 15:32:05 +0000 Subject: [PATCH 101/191] Removed unused environment variables --- test/api/Connection/connection_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/api/Connection/connection_test.go b/test/api/Connection/connection_test.go index 8de08811..cab38c07 100644 --- a/test/api/Connection/connection_test.go +++ b/test/api/Connection/connection_test.go @@ -1,13 +1,13 @@ package api_test import ( - "github.com/stretchr/testify/require" "testing" - "github.com/Telmate/proxmox-api-go/test/api" + + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" ) func Test_Connection_Certificate_No_Validation(t *testing.T) { - api_test.SetEnvironmentVariables() Test := api_test.Test{ RequireSSL: false, } @@ -16,10 +16,9 @@ func Test_Connection_Certificate_No_Validation(t *testing.T) { } func Test_Connection_Certificate_Validation(t *testing.T) { - api_test.SetEnvironmentVariables() Test := api_test.Test{ RequireSSL: true, } err := Test.CreateTest() require.Error(t, err) -} \ No newline at end of file +} From fda075cd72e18f558a9b470d32aad01f92bf9a89 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 15:32:21 +0000 Subject: [PATCH 102/191] User management test movearound --- test/api/UserManagement/list_user_test.go | 18 ++++++++++ .../UserManagement/user_management_test.go | 33 ++++++++----------- 2 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 test/api/UserManagement/list_user_test.go diff --git a/test/api/UserManagement/list_user_test.go b/test/api/UserManagement/list_user_test.go new file mode 100644 index 00000000..f3a100b1 --- /dev/null +++ b/test/api/UserManagement/list_user_test.go @@ -0,0 +1,18 @@ +package api_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" +) + +func Test_List_Users(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + users, err := pxapi.ListUsers(Test.GetClient(), false) + require.NoError(t, err) + require.Equal(t, 1, len(*users)) +} diff --git a/test/api/UserManagement/user_management_test.go b/test/api/UserManagement/user_management_test.go index 97694462..ce47f59e 100644 --- a/test/api/UserManagement/user_management_test.go +++ b/test/api/UserManagement/user_management_test.go @@ -1,37 +1,30 @@ package api_test import ( - "github.com/stretchr/testify/require" "testing" -// "os" - "github.com/Telmate/proxmox-api-go/test/api" + + "github.com/stretchr/testify/require" + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" ) var user = pxapi.ConfigUser{ User: pxapi.UserID{ Name: "Bob", Realm: "pve", - }, - Comment: "", - Email: "bob@example.com", - Enable: true, - FirstName: "Bob", - LastName: "Bobson", -} - -func Test_List_Users(t *testing.T) { - Test := api_test.Test{} - _ = Test.CreateTest() - users, err := pxapi.ListUsers(Test.GetClient(), false) - require.NoError(t, err) - require.Equal(t, 1, len(*users)) + }, + Comment: "", + Email: "bob@example.com", + Enable: true, + FirstName: "Bob", + LastName: "Bobson", } func Test_Create_User(t *testing.T) { - Test := api_test.Test {} + Test := api_test.Test{} _ = Test.CreateTest() - err := user.CreateUser(Test.GetClient()) + err := user.CreateUser(Test.GetClient()) require.NoError(t, err) } @@ -51,7 +44,7 @@ func Test_User_Is_Added(t *testing.T) { } func Test_Remove_User(t *testing.T) { - Test := api_test.Test {} + Test := api_test.Test{} _ = Test.CreateTest() err := user.DeleteUser(Test.GetClient()) require.NoError(t, err) From ad16ae23ec6de1313f5b1575cd8b905ef9375e1b Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 15:32:30 +0000 Subject: [PATCH 103/191] Qemu VM tests --- Vagrantfile | 6 ++ test/api/Qemu/qemu_clone.go | 52 +++++++++++++++++ .../Qemu/qemu_create_update_delete_test.go | 56 +++++++++++++++++++ test/api/Qemu/qemu_start_test.go | 38 +++++++++++++ test/api/Qemu/shared_test.go | 56 +++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 test/api/Qemu/qemu_clone.go create mode 100644 test/api/Qemu/qemu_create_update_delete_test.go create mode 100644 test/api/Qemu/qemu_start_test.go create mode 100644 test/api/Qemu/shared_test.go diff --git a/Vagrantfile b/Vagrantfile index 196b3eb4..7c4d81fd 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -21,6 +21,12 @@ Vagrant.configure("2") do |config| vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"] end + config.vm.provider :hyperv do |hv| + hv.memory = 2048 + hv.cpus = 2 + hv.enable_virtualization_extensions = true + end + config.vm.provider :vmware do |vm| vm.vmx["memsize"] = "2048" vm.vmx["numvcpus"] = "2" diff --git a/test/api/Qemu/qemu_clone.go b/test/api/Qemu/qemu_clone.go new file mode 100644 index 00000000..93d85191 --- /dev/null +++ b/test/api/Qemu/qemu_clone.go @@ -0,0 +1,52 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func _create_clone_vmref() (ref *pxapi.VmRef) { + ref = pxapi.NewVmRef(100) + ref.SetNode("pve") + ref.SetVmType("qemu") + return ref +} + +func Test_Clone_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + config := _create_vm_spec(false) + + config.CreateVm(_create_vmref(), Test.GetClient()) + + cloneConfig := _create_vm_spec(false) + + fullClone := 1 + + cloneConfig.Name = "test-qemu02" + cloneConfig.FullClone = &fullClone + + err := cloneConfig.CloneVm(_create_vmref(), _create_clone_vmref(), Test.GetClient()) + + require.NoError(t, err) + +} + +func Test_Qemu_VM_Is_Cloned(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigQemuFromApi(_create_clone_vmref(), Test.GetClient()) + + require.Equal(t, "order=ide2;net0", config.Boot) +} + +func Test_Clone_Qemu_VM_Cleanup(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + Test.GetClient().DeleteVm(_create_clone_vmref()) + Test.GetClient().DeleteVm(_create_vmref()) +} diff --git a/test/api/Qemu/qemu_create_update_delete_test.go b/test/api/Qemu/qemu_create_update_delete_test.go new file mode 100644 index 00000000..30498821 --- /dev/null +++ b/test/api/Qemu/qemu_create_update_delete_test.go @@ -0,0 +1,56 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Create_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + config := _create_vm_spec(true) + + err := config.CreateVm(_create_vmref(), Test.GetClient()) + require.NoError(t, err) +} + +func Test_Qemu_VM_Is_Added(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigQemuFromApi(_create_vmref(), Test.GetClient()) + + require.Equal(t, "order=ide2;net0", config.Boot) +} + +func Test_Update_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config := _create_vm_spec(true) + + config.Boot = "order=net0;ide2" + + err := config.UpdateConfig(_create_vmref(), Test.GetClient()) + + require.NoError(t, err) +} + +func Test_Qemu_VM_Is_Updated(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigQemuFromApi(_create_vmref(), Test.GetClient()) + require.Equal(t, "order=net0;ide2", config.Boot) +} + +func Test_Remove_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + _, err := Test.GetClient().DeleteVm(_create_vmref()) + + require.NoError(t, err) +} diff --git a/test/api/Qemu/qemu_start_test.go b/test/api/Qemu/qemu_start_test.go new file mode 100644 index 00000000..cd5f81b2 --- /dev/null +++ b/test/api/Qemu/qemu_start_test.go @@ -0,0 +1,38 @@ +package api_test + +import ( + "testing" + + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Start_Stop_Qemu_VM_Setup(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config := _create_vm_spec(false) + config.CreateVm(_create_vmref(), Test.GetClient()) +} + +func Test_Start_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := Test.GetClient().StartVm(_create_vmref()) + require.NoError(t, err) +} + +func Test_Stop_Qemu_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := Test.GetClient().StopVm(_create_vmref()) + require.NoError(t, err) +} + +func Test_Start_Stop_Qemu_VM_Cleanup(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + Test.GetClient().DeleteVm(_create_vmref()) +} diff --git a/test/api/Qemu/shared_test.go b/test/api/Qemu/shared_test.go new file mode 100644 index 00000000..c73a8c85 --- /dev/null +++ b/test/api/Qemu/shared_test.go @@ -0,0 +1,56 @@ +package api_test + +import ( + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +func _create_vmref() (ref *pxapi.VmRef) { + ref = pxapi.NewVmRef(100) + ref.SetNode("pve") + ref.SetVmType("qemu") + return ref +} + +func BoolPointer(b bool) *bool { + return &b +} + +func _create_vm_spec(network bool) pxapi.ConfigQemu { + + disks := make(pxapi.QemuDevices) + disks[0] = make(map[string]interface{}) + disks[0]["type"] = "virtio" + disks[0]["storage"] = "local" + disks[0]["size"] = "1G" + + networks := make(pxapi.QemuDevices) + if network { + networks[0] = make(map[string]interface{}) + networks[0]["bridge"] = "vmbr0" + networks[0]["firewall"] = "true" + networks[0]["id"] = "0" + networks[0]["macaddr"] = "B6:8F:9D:7C:8F:BC" + networks[0]["model"] = "virtio" + } + + config := pxapi.ConfigQemu{ + Name: "test-qemu01", + Bios: "seabios", + Tablet: pxapi.PointerBool(true), + Memory: 128, + QemuOs: "l26", + QemuCores: 1, + QemuSockets: 1, + QemuCpu: "host", + QemuNuma: pxapi.PointerBool(false), + QemuKVM: pxapi.PointerBool(true), + Hotplug: "network,disk,usb", + QemuNetworks: networks, + QemuIso: "none", + Boot: "order=ide2;net0", + Scsihw: "virtio-scsi-pci", + QemuDisks: disks, + } + + return config +} From 6170249a0d78eaece413a90accbbe852dfe74063 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 19:52:18 +0000 Subject: [PATCH 104/191] Moved some tests around to standardise naming --- ...ount_test.go => acme_account_create_remove_test.go} | 10 ++++++---- ..._acme_account_test.go => acme_account_list_test.go} | 0 test/api/Qemu/shared_test.go | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) rename test/api/AcmeAccount/{acme_account_test.go => acme_account_create_remove_test.go} (88%) rename test/api/AcmeAccount/{list_acme_account_test.go => acme_account_list_test.go} (100%) diff --git a/test/api/AcmeAccount/acme_account_test.go b/test/api/AcmeAccount/acme_account_create_remove_test.go similarity index 88% rename from test/api/AcmeAccount/acme_account_test.go rename to test/api/AcmeAccount/acme_account_create_remove_test.go index 9c2d8bab..c6c7655c 100644 --- a/test/api/AcmeAccount/acme_account_test.go +++ b/test/api/AcmeAccount/acme_account_create_remove_test.go @@ -1,11 +1,13 @@ package api_test import ( - "github.com/stretchr/testify/require" "testing" + + "github.com/stretchr/testify/require" + // "os" - "github.com/Telmate/proxmox-api-go/test/api" pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" ) var account = ` @@ -21,7 +23,7 @@ var account = ` }` func Test_Create_Acme_Account(t *testing.T) { - Test := api_test.Test {} + Test := api_test.Test{} _ = Test.CreateTest() acmeAccount, _ := pxapi.NewConfigAcmeAccountFromJson([]byte(account)) err := acmeAccount.CreateAcmeAccount("test", Test.GetClient()) @@ -38,7 +40,7 @@ func Test_Acme_Account_Is_Added(t *testing.T) { } func Test_Remove_Acme_Account(t *testing.T) { - Test := api_test.Test {} + Test := api_test.Test{} _ = Test.CreateTest() _, err := Test.GetClient().DeleteAcmeAccount("test") diff --git a/test/api/AcmeAccount/list_acme_account_test.go b/test/api/AcmeAccount/acme_account_list_test.go similarity index 100% rename from test/api/AcmeAccount/list_acme_account_test.go rename to test/api/AcmeAccount/acme_account_list_test.go diff --git a/test/api/Qemu/shared_test.go b/test/api/Qemu/shared_test.go index c73a8c85..d4f1e3f8 100644 --- a/test/api/Qemu/shared_test.go +++ b/test/api/Qemu/shared_test.go @@ -41,7 +41,7 @@ func _create_vm_spec(network bool) pxapi.ConfigQemu { QemuOs: "l26", QemuCores: 1, QemuSockets: 1, - QemuCpu: "host", + QemuCpu: "kvm64", QemuNuma: pxapi.PointerBool(false), QemuKVM: pxapi.PointerBool(true), Hotplug: "network,disk,usb", From 024f491d362c18ce21f990d74b4b02824f42b885 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 19:52:34 +0000 Subject: [PATCH 105/191] Created Pool tests --- test/api/Pool/pool_create_destroy_test.go | 34 +++++++++++++++++++++++ test/api/Pool/pool_list_test.go | 16 +++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/api/Pool/pool_create_destroy_test.go create mode 100644 test/api/Pool/pool_list_test.go diff --git a/test/api/Pool/pool_create_destroy_test.go b/test/api/Pool/pool_create_destroy_test.go new file mode 100644 index 00000000..2c90158c --- /dev/null +++ b/test/api/Pool/pool_create_destroy_test.go @@ -0,0 +1,34 @@ +package api_test + +import ( + "testing" + + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Pool_Create(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + Test.GetClient().CreatePool("test-pool", "Test pool") +} + +func Test_Pool_Is_Created(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + _, err := Test.GetClient().GetPoolInfo("test-pool") + require.NoError(t, err) +} + +func Test_Pool_Delete(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + Test.GetClient().DeletePool("test-pool") +} + +func Test_Pool_Is_Deleted(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + _, err := Test.GetClient().GetPoolInfo("test-pool") + require.Error(t, err) +} diff --git a/test/api/Pool/pool_list_test.go b/test/api/Pool/pool_list_test.go new file mode 100644 index 00000000..d14656e0 --- /dev/null +++ b/test/api/Pool/pool_list_test.go @@ -0,0 +1,16 @@ +package api_test + +import ( + "testing" + + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Pools_List(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + pools, err := Test.GetClient().GetPoolList() + require.NoError(t, err) + require.Equal(t, 1, len(pools)) +} From 34b6ee83448e46d1cc3968afd49e3d5fe3f9a4e4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:43:15 +0000 Subject: [PATCH 106/191] feat: add custom type and validate func --- proxmox/config_qemu_disk.go | 90 +++++++--- proxmox/config_qemu_disk_test.go | 132 ++++++++++++--- proxmox/config_qemu_test.go | 272 +++++++++++++++---------------- 3 files changed, 312 insertions(+), 182 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index d2691913..702994f7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -334,19 +334,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "iops_rd" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Concurrent = uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) } if e[0] == "iops_rd_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Burst = uint(tmp) + disk.Bandwidth.Iops.ReadLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Concurrent = uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) } if e[0] == "iops_wr_max" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Burst = uint(tmp) + disk.Bandwidth.Iops.WriteLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) @@ -354,19 +354,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "mbps_rd" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Concurrent = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Concurrent = QemuDiskBandwidthDataLimitConcurrent(math.Round(tmp*100) / 100) } if e[0] == "mbps_rd_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Burst = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.ReadLimit.Burst = QemuDiskBandwidthDataLimitBurst(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Concurrent = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Concurrent = QemuDiskBandwidthDataLimitConcurrent(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Burst = float32(math.Round(tmp*100) / 100) + disk.Bandwidth.Data.WriteLimit.Burst = QemuDiskBandwidthDataLimitBurst(math.Round(tmp*100) / 100) } if e[0] == "replicate" { disk.Replicate, _ = strconv.ParseBool(e[1]) @@ -475,21 +475,40 @@ func (data QemuDiskBandwidthData) Validate() error { } type QemuDiskBandwidthDataLimit struct { - Burst float32 `json:"burst,omitempty"` // 0 = default - Concurrent float32 `json:"concurrent,omitempty"` // 0 = unlimited + Burst QemuDiskBandwidthDataLimitBurst `json:"burst,omitempty"` // 0 = default + Concurrent QemuDiskBandwidthDataLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited +} + +func (limit QemuDiskBandwidthDataLimit) Validate() (err error) { + if err = limit.Burst.Validate(); err != nil { + return + } + err = limit.Concurrent.Validate() + return } const ( - Error_QemuDiskBandwidthDataLimit_Burst string = "burst may not be lower then 1 except for 0" - Error_QemuDiskBandwidthDataLimit_Concurrent string = "concurrent may not be lower then 1 except for 0" + Error_QemuDiskBandwidthDataLimitBurst string = "burst may not be lower then 1 except for 0" ) -func (limit QemuDiskBandwidthDataLimit) Validate() error { - if limit.Burst != 0 && limit.Burst < 1 { - return errors.New(Error_QemuDiskBandwidthDataLimit_Burst) +type QemuDiskBandwidthDataLimitBurst float32 + +func (limit QemuDiskBandwidthDataLimitBurst) Validate() error { + if limit != 0 && limit < 1 { + return errors.New(Error_QemuDiskBandwidthDataLimitBurst) } - if limit.Concurrent != 0 && limit.Concurrent < 1 { - return errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) + return nil +} + +const ( + Error_QemuDiskBandwidthDataLimitConcurrent string = "concurrent may not be lower then 1 except for 0" +) + +type QemuDiskBandwidthDataLimitConcurrent float32 + +func (limit QemuDiskBandwidthDataLimitConcurrent) Validate() error { + if limit != 0 && limit < 1 { + return errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) } return nil } @@ -508,21 +527,40 @@ func (iops QemuDiskBandwidthIops) Validate() error { } type QemuDiskBandwidthIopsLimit struct { - Burst uint `json:"burst,omitempty"` // 0 = default - Concurrent uint `json:"concurrent,omitempty"` // 0 = unlimited + Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = default + Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } +func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { + if err = limit.Burst.Validate(); err != nil { + return + } + err = limit.Concurrent.Validate() + return +} + +type QemuDiskBandwidthIopsLimitBurst uint + const ( - Error_QemuDiskBandwidthIopsLimit_Burst string = "burst may not be lower then 10 except for 0" - Error_QemuDiskBandwidthIopsLimit_Concurrent string = "concurrent may not be lower then 10 except for 0" + Error_QemuDiskBandwidthIopsLimitBurst string = "burst may not be lower then 10 except for 0" ) -func (limit QemuDiskBandwidthIopsLimit) Validate() error { - if limit.Burst != 0 && limit.Burst < 10 { - return errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) +func (limit QemuDiskBandwidthIopsLimitBurst) Validate() error { + if limit != 0 && limit < 10 { + return errors.New(Error_QemuDiskBandwidthIopsLimitBurst) } - if limit.Concurrent != 0 && limit.Concurrent < 10 { - return errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) + return nil +} + +type QemuDiskBandwidthIopsLimitConcurrent uint + +const ( + Error_QemuDiskBandwidthIopsLimitConcurrent string = "concurrent may not be lower then 10 except for 0" +) + +func (limit QemuDiskBandwidthIopsLimitConcurrent) Validate() error { + if limit != 0 && limit < 10 { + return errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 1370e50f..39a54492 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -145,14 +145,14 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { {name: "Valid 21", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, {name: "Valid 22", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {name: "Invalid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {name: "Invalid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {name: "Invalid 04", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {name: "Invalid 05", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, - {name: "Invalid 06", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {name: "Invalid 07", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 04", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 05", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 06", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 07", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -184,10 +184,10 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { {name: "Valid 09", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, {name: "Valid 10", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {name: "Invalid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {name: "Invalid 03", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -213,8 +213,54 @@ func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { {name: "Valid 03", input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, {name: "Valid 04", input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst)}, - {name: "Invalid 01", input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + +func Test_QemuDiskBandwidthDataLimitBurst_Validate(t *testing.T) { + testData := []struct { + name string + input QemuDiskBandwidthDataLimitBurst + err error + }{ + // Valid + {name: "Valid 01", input: 0}, + {name: "Valid 02", input: 1}, + // Invalid + {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + +func Test_QemuDiskBandwidthDataLimitConcurrent_Validate(t *testing.T) { + testData := []struct { + name string + input QemuDiskBandwidthDataLimitConcurrent + err error + }{ + // Valid + {name: "Valid 01", input: 0}, + {name: "Valid 02", input: 1}, + // Invalid + {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -246,10 +292,10 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { {name: "Valid 09", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, {name: "Valid 10", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {name: "Invalid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {name: "Invalid 03", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -275,8 +321,54 @@ func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { {name: "Valid 03", input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, {name: "Valid 04", input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst)}, - {name: "Invalid 01", input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + +func Test_QemuDiskBandwidthIopsLimitBurst_Validate(t *testing.T) { + testData := []struct { + name string + input QemuDiskBandwidthIopsLimitBurst + err error + }{ + // Valid + {name: "Valid 03", input: 0}, + {name: "Valid 04", input: 10}, + // Invalid + {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + } + for _, test := range testData { + t.Run(test.name, func(*testing.T) { + if test.err != nil { + require.Equal(t, test.input.Validate(), test.err, test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + +func Test_QemuDiskBandwidthIopsLimitConcurrent_Validate(t *testing.T) { + testData := []struct { + name string + input QemuDiskBandwidthIopsLimitConcurrent + err error + }{ + // Valid + {name: "Valid 03", input: 0}, + {name: "Valid 04", input: 10}, + // Invalid + {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 31034762..8f653729 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -11,14 +11,14 @@ import ( func Test_ConfigQemu_mapToApiValues(t *testing.T) { format_Raw := QemuDiskFormat_Raw - float10 := float32(10.3) - float45 := float32(45.23) - float79 := float32(79.23) - float99 := float32(99.2) - uint23 := uint(23) - uint34 := uint(34) - uint78 := uint(78) - uint89 := uint(89) + float10 := QemuDiskBandwidthDataLimitConcurrent(10.3) + float45 := QemuDiskBandwidthDataLimitConcurrent(45.23) + float79 := QemuDiskBandwidthDataLimitBurst(79.23) + float99 := QemuDiskBandwidthDataLimitBurst(99.2) + uint23 := QemuDiskBandwidthIopsLimitConcurrent(23) + uint34 := QemuDiskBandwidthIopsLimitConcurrent(34) + uint78 := QemuDiskBandwidthIopsLimitBurst(78) + uint89 := QemuDiskBandwidthIopsLimitBurst(89) update_CloudInit := &QemuCloudInitDisk{Format: QemuDiskFormat_Raw, Storage: "test"} ideBase := &QemuIdeStorage{Disk: &QemuIdeDisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} sataBase := &QemuSataStorage{Disk: &QemuSataDisk{Format: QemuDiskFormat_Raw, Id: 23, Size: 10, Storage: "test"}} @@ -4272,37 +4272,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Disk Ide QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Cache: "invalid"}}}}}, @@ -4350,37 +4350,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Disk Sata QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Cache: "invalid"}}}}}, @@ -4428,37 +4428,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Disk Scsi QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Cache: "invalid"}}}}}, @@ -4506,37 +4506,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Disk VirtIO QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Cache: "invalid"}}}}}, @@ -4580,37 +4580,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Passthrough Ide QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Cache: "invalid"}}}}}, @@ -4633,37 +4633,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Passthrough Sata QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Cache: "invalid"}}}}}, @@ -4686,37 +4686,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Passthrough Scsi QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Cache: "invalid"}}}}}, @@ -4739,37 +4739,37 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 0`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Burst) 1`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 0`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 0`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 8}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Burst) 1`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 7}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Burst), + err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent) 1`, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) 1`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthIopsLimit_Concurrent), + err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, {name: `Invalid Disks Passthrough VirtIO QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Cache: "invalid"}}}}}, From 429c0d7461a2a2e01f268bf29815309558847de8 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:44:23 +0000 Subject: [PATCH 107/191] refactor: cahange update flow --- proxmox/config_qemu.go | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index c0ed60bb..4eda9af2 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -675,7 +675,7 @@ func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { if err != nil { return } - return newConfig.UpdateAdvanced(currentConfig, vmr, client) + return newConfig.SetAdvanced(currentConfig, vmr, client) } func (config *ConfigQemu) setVmr(vmr *VmRef) error { @@ -690,7 +690,7 @@ func (config *ConfigQemu) setVmr(vmr *VmRef) error { return nil } -func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { +func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { err = newConfig.setVmr(vmr) if err != nil { return @@ -700,14 +700,21 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef return } + var params map[string]interface{} + var exitStatus string + if currentConfig != nil { + // Update + markedDisks := newConfig.Disks.markDiskChanges(*currentConfig.Disks) + // move disk to different storage or change disk format for _, e := range markedDisks.Move { _, err = e.move(true, vmr, client) if err != nil { return } } + // increase Disks in size for _, e := range markedDisks.Resize { _, err = e.resize(vmr, client) if err != nil { @@ -721,30 +728,35 @@ func (newConfig ConfigQemu) UpdateAdvanced(currentConfig *ConfigQemu, vmr *VmRef return } } - } - if newConfig.Node != currentConfig.Node { - vmr.SetNode(currentConfig.Node) - _, err = client.MigrateNode(vmr, newConfig.Node, true) - if err != nil { - return + // Migrate VM + if newConfig.Node != currentConfig.Node { + vmr.SetNode(currentConfig.Node) + _, err = client.MigrateNode(vmr, newConfig.Node, true) + if err != nil { + return + } + // Set node to the node the VM was migrated to + vmr.SetNode(newConfig.Node) } - vmr.SetNode(newConfig.Node) - } - var params map[string]interface{} - if currentConfig != nil { params, err = newConfig.mapToApiValues(*currentConfig) + if err != nil { + return + } + exitStatus, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") } else { + // Create + params, err = newConfig.mapToApiValues(ConfigQemu{}) - } - if err != nil { - return + if err != nil { + return + } + exitStatus, err = client.CreateQemuVm(vmr.node, params) } - _, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") if err != nil { - return + return fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) } _, err = client.UpdateVMHA(vmr, newConfig.HaState, newConfig.HaGroup) From 65996e1b95fa23ad734e7a2ec7ac68a601a574ed Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:45:10 +0000 Subject: [PATCH 108/191] refactor: add new `ConfigQemu{}.Create` func --- proxmox/config_qemu.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 4eda9af2..ec6bb7ba 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -87,6 +87,13 @@ type ConfigQemu struct { VmID int `json:"vmid,omitempty"` // TODO should be a custom type as there are limitations } +// Create - Tell Proxmox API to make the VM +func (config ConfigQemu) Create(vmr *VmRef, client *Client) error { + return config.SetAdvanced(nil, vmr, client) +} + +// DEPRECATED use ConfigQemu{}.Create Instead. +// // CreateVm - Tell Proxmox API to make the VM func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { err = config.setVmr(vmr) From 6a66cf1806cfa471d7e31d4a642f78783bc9bcb8 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:47:16 +0000 Subject: [PATCH 109/191] docs: add comment --- proxmox/config_qemu_disk.go | 1 + 1 file changed, 1 insertion(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 702994f7..57724459 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -884,6 +884,7 @@ func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { return nil } +// mark disk that need to be moved or resized func (storages QemuStorages) markDiskChanges(currentStorages QemuStorages) *qemuUpdateChanges { changes := &qemuUpdateChanges{} if storages.Ide != nil { From ff3477116a71969152b0ce4dde54ac66643c3638 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Mon, 20 Mar 2023 22:41:41 +0000 Subject: [PATCH 110/191] Renamed qemu_clone.go to qemu_clone_test.go, as it should have been --- test/api/Qemu/{qemu_clone.go => qemu_clone_test.go} | 0 test/api/Qemu/shared_test.go | 4 ---- 2 files changed, 4 deletions(-) rename test/api/Qemu/{qemu_clone.go => qemu_clone_test.go} (100%) diff --git a/test/api/Qemu/qemu_clone.go b/test/api/Qemu/qemu_clone_test.go similarity index 100% rename from test/api/Qemu/qemu_clone.go rename to test/api/Qemu/qemu_clone_test.go diff --git a/test/api/Qemu/shared_test.go b/test/api/Qemu/shared_test.go index d4f1e3f8..8999116d 100644 --- a/test/api/Qemu/shared_test.go +++ b/test/api/Qemu/shared_test.go @@ -11,10 +11,6 @@ func _create_vmref() (ref *pxapi.VmRef) { return ref } -func BoolPointer(b bool) *bool { - return &b -} - func _create_vm_spec(network bool) pxapi.ConfigQemu { disks := make(pxapi.QemuDevices) From bf4101fb0834edbf3581e9811cd708ac78f64c54 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Tue, 21 Mar 2023 14:18:26 +0000 Subject: [PATCH 111/191] Added Api Token create/update/delete New functions on the ConfigUser object to create, list, update and delete API tokens New structs to hold an API token, and the results of creating an API token --- proxmox/config_user.go | 80 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/proxmox/config_user.go b/proxmox/config_user.go index 1c49cbfc..13833760 100644 --- a/proxmox/config_user.go +++ b/proxmox/config_user.go @@ -172,6 +172,86 @@ func (config ConfigUser) UpdateUserPassword(client *Client) (err error) { }, "/access/password") } +type ApiToken struct { + TokenId string `json:"tokenid"` + Comment string `json:"comment,omitempty"` + Expire int64 `json:"expire"` + Privsep bool `json:"privsep"` +} +type ApiTokenCreateResult struct { + Info map[string]interface{} `json:"info"` + Value string `json:"value"` +} +type ApiTokenCreateResultWrapper struct { + Data ApiTokenCreateResult `json:"data"` +} + +// Maps the API values from proxmox to a struct +func (tokens ApiToken) mapToStruct(params map[string]interface{}) *ApiToken { + if _, isSet := params["tokenid"]; isSet { + tokens.TokenId = params["tokenid"].(string) + } + if _, isSet := params["comment"]; isSet { + tokens.Comment = params["comment"].(string) + } + if _, isSet := params["expire"]; isSet { + tokens.Expire = int64(params["expire"].(float64)) + } + if _, isSet := params["privsep"]; isSet { + tokens.Privsep = false + if params["privsep"] == 1 { + tokens.Privsep = true + } + } + return &tokens +} + +func (ApiToken) mapToArray(params []interface{}) *[]ApiToken { + tokens := make([]ApiToken, len(params)) + for i, e := range params { + tokens[i] = *ApiToken{}.mapToStruct(e.(map[string]interface{})) + } + return &tokens +} + +func (config ConfigUser) CreateApiToken(client *Client, token ApiToken) (value string, err error) { + status, err := client.CreateItemReturnStatus(map[string]interface{}{ + "comment": token.Comment, + "expire": token.Expire, + "privsep": token.Privsep, + }, "/access/users/"+config.User.ToString()+"/token/"+token.TokenId) + if err != nil { + return + } + var resultWrapper *ApiTokenCreateResultWrapper + err = json.Unmarshal([]byte(status), &resultWrapper) + value = resultWrapper.Data.Value + return +} + +func (config ConfigUser) UpdateApiToken(client *Client, token ApiToken) (err error) { + err = client.Put(map[string]interface{}{ + "comment": token.Comment, + "expire": token.Expire, + "privsep": token.Privsep, + }, "/access/users/"+config.User.ToString()+"/token/"+token.TokenId) + return +} + +func (config ConfigUser) ListApiTokens(client *Client) (tokens *[]ApiToken, err error) { + status, err := client.GetItemListInterfaceArray("/access/users/" + config.User.ToString() + "/token") + if err != nil { + return + } + tokens = ApiToken{}.mapToArray(status) + return +} + +func (config ConfigUser) DeleteApiToken(client *Client, token ApiToken) (err error) { + err = client.Delete("/access/users/" + config.User.ToString() + "/token/" + token.TokenId) + return +} + // Validates all items and sub items in the ConfigUser struct func (config ConfigUser) Validate() (err error) { err = config.User.Validate() From 362c4c456d299abee7211c0bf9ede7e2bb62282d Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Tue, 21 Mar 2023 14:28:28 +0000 Subject: [PATCH 112/191] Added tests for the API keys - Test create / Update / Delete - Test authentication using the API keys --- .../authentication_apikey_test.go | 29 +++++++ test/api/UserManagement/create_token_test.go | 81 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 test/api/Authentication/authentication_apikey_test.go create mode 100644 test/api/UserManagement/create_token_test.go diff --git a/test/api/Authentication/authentication_apikey_test.go b/test/api/Authentication/authentication_apikey_test.go new file mode 100644 index 00000000..4a7bc7b1 --- /dev/null +++ b/test/api/Authentication/authentication_apikey_test.go @@ -0,0 +1,29 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Root_Login_Correct_Api_Key(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + token := pxapi.ApiToken{TokenId: "testing", Comment: "This is a test", Expire: 0, Privsep: false} + + value, err := user.CreateApiToken(Test.GetClient(), token) + + NewTest := api_test.Test{} + NewTest.CreateClient() + NewTest.GetClient().SetAPIToken("root@pam!testing", value) + + _, err = NewTest.GetClient().GetVersion() + require.NoError(t, err) + + user.DeleteApiToken(Test.GetClient(), token) +} diff --git a/test/api/UserManagement/create_token_test.go b/test/api/UserManagement/create_token_test.go new file mode 100644 index 00000000..80bc1725 --- /dev/null +++ b/test/api/UserManagement/create_token_test.go @@ -0,0 +1,81 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Create_Token(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + _, err := user.CreateApiToken(Test.GetClient(), pxapi.ApiToken{TokenId: "testing", Comment: "This is a test", Expire: 1679404904, Privsep: true}) + require.NoError(t, err) +} + +func Test_Token_Is_Created(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + tokens, _ := user.ListApiTokens(Test.GetClient()) + + listoftokens := *tokens + + t.Log(listoftokens[0].TokenId) + require.Equal(t, "testing", listoftokens[0].TokenId) +} + +func Test_Update_Token(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + tokens, _ := user.ListApiTokens(Test.GetClient()) + + listoftokens := *tokens + + listoftokens[0].Comment = "New Comment" + + err := user.UpdateApiToken(Test.GetClient(), listoftokens[0]) + require.NoError(t, err) +} + +func Test_Token_Is_Updated(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + tokens, _ := user.ListApiTokens(Test.GetClient()) + + listoftokens := *tokens + + require.Equal(t, "New Comment", listoftokens[0].Comment) +} + +func Test_Delete_Token(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + tokens, _ := user.ListApiTokens(Test.GetClient()) + + listoftokens := *tokens + + err := user.DeleteApiToken(Test.GetClient(), listoftokens[0]) + require.NoError(t, err) +} + +func Test_Token_Is_Deleted(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + user, _ := pxapi.NewConfigUserFromApi(pxapi.UserID{Name: "root", Realm: "pam"}, Test.GetClient()) + + tokens, _ := user.ListApiTokens(Test.GetClient()) + + require.Equal(t, 0, len(*tokens)) +} From e79247d189085f2e20426a85a9748701b1816129 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Tue, 21 Mar 2023 17:59:04 +0100 Subject: [PATCH 113/191] Fix GetTaskExitStatus success criteria GetTaskExitStatus considers any exitstatus other than "OK" as an error. But the Proxmox API can return "WARNINGS: XXX" in the some cases. This should be considered a success as well. This bug causes the Terraform provider to try to start the VM three times, and then to return an error because all attempts apparently "fail" (but the VM is actually correctly started). Example output when starting a VM: POST /api2/json/nodes/dahu-2/qemu/100/status/start GET /api2/json/nodes/dahu-2/tasks/UPID:dahu-2:00007323:001036A5:6419CAF8:qmstart:100:root@pam:/status {"data":{"id":"100","pid":29475,"status":"stopped","type":"qmstart","pstart":1062565,"exitstatus":"WARNINGS: 1","upid":"UPID:dahu-2:00007323:001036A5:6419CAF8:qmstart:100:root@pam:","starttime":1679411960,"user":"root@pam","node":"dahu-2"}} The exit status is "WARNINGS: 1", not "OK", but the operation still worked. The corresponding warning in the web interface is: WARN: no efidisk configured! Using temporary efivars disk. TASK WARNINGS: 1 --- proxmox/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index 5c80279b..b1edab45 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -444,6 +444,7 @@ func (c *Client) WaitForCompletion(taskResponse map[string]interface{}) (waitExi } var rxTaskNode = regexp.MustCompile("UPID:(.*?):") +var rxExitStatusSuccess = regexp.MustCompile(`^(OK|WARNINGS)`) func (c *Client) GetTaskExitstatus(taskUpid string) (exitStatus interface{}, err error) { node := rxTaskNode.FindStringSubmatch(taskUpid)[1] @@ -453,7 +454,7 @@ func (c *Client) GetTaskExitstatus(taskUpid string) (exitStatus interface{}, err if err == nil { exitStatus = data["data"].(map[string]interface{})["exitstatus"] } - if exitStatus != nil && exitStatus != exitStatusSuccess { + if exitStatus != nil && rxExitStatusSuccess.FindString(exitStatus.(string)) == "" { err = fmt.Errorf(exitStatus.(string)) } return From cebcfff9008b3293db9246dc324957d9b1ca69d3 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:57:26 +0000 Subject: [PATCH 114/191] refactor: move `VmRef` nilCheck to new func --- proxmox/client.go | 7 +++++++ proxmox/config_qemu.go | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index 2b73d67f..2ea537b8 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -81,6 +81,13 @@ func (vmr *VmRef) HaGroup() string { return vmr.haGroup } +func (vmr *VmRef) nilCheck() error { + if vmr == nil { + return errors.New("vm reference may not be nil") + } + return nil +} + func NewVmRef(vmId int) (vmr *VmRef) { vmr = &VmRef{vmId: vmId, node: "", vmType: ""} return diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index ec6bb7ba..6805c95a 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -685,16 +685,16 @@ func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { return newConfig.SetAdvanced(currentConfig, vmr, client) } -func (config *ConfigQemu) setVmr(vmr *VmRef) error { +func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) { if config == nil { return errors.New("config may not be nil") } - if vmr == nil { - return errors.New("vm reference may not be nil") + if err = vmr.nilCheck(); err != nil { + return } vmr.SetVmType("qemu") config.VmID = vmr.vmId - return nil + return } func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { From 0ca2aff7edc7373c4f48b511c09fb009b1575f78 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 23 Mar 2023 15:22:15 +0000 Subject: [PATCH 115/191] feat: add func for checking if a key exists in an `[]interface{map[string]interface{}}` --- proxmox/util.go | 11 +++++++++++ proxmox/util_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/proxmox/util.go b/proxmox/util.go index 253fa4ea..f1c4fcfe 100644 --- a/proxmox/util.go +++ b/proxmox/util.go @@ -205,6 +205,17 @@ func createHeaderList(header_string string, sess *Session) (*Session, error) { return sess, nil } +// check if a key exists in a nested array of map[string]interface{} +func keyExists(array []interface{}, key string) (existence bool) { + for i := range array { + item := array[i].(map[string]interface{}) + if _, isSet := item[key]; isSet { + return true + } + } + return false +} + func splitStringOfSettings(settings string) (settingArray [][]string) { settingValuePairs := strings.Split(settings, ",") settingArray = make([][]string, len(settingValuePairs)) diff --git a/proxmox/util_test.go b/proxmox/util_test.go index 38b2c45a..db842767 100644 --- a/proxmox/util_test.go +++ b/proxmox/util_test.go @@ -6,6 +6,52 @@ import ( "github.com/stretchr/testify/require" ) +func Test_keyExists(t *testing.T) { + tests := []struct { + name string + input []interface{} + key string + output bool + }{ + {name: "key empty", + input: []interface{}{ + map[string]interface{}{"aaa": "", "bbb": "", "ccc": ""}, + map[string]interface{}{"aab": "", "bba": "", "cca": ""}, + map[string]interface{}{"aac": "", "bbc": "", "ccb": ""}, + }, + }, + {name: "Key in map", + input: []interface{}{ + map[string]interface{}{"aaa": "", "bbb": "", "ccc": ""}, + map[string]interface{}{"aab": "", "bba": "", "cca": ""}, + map[string]interface{}{"aac": "", "bbc": "", "ccb": ""}, + }, + key: "bba", + output: true, + }, + {name: "Key not in map", + input: []interface{}{ + map[string]interface{}{"aaa": "", "bbb": "", "ccc": ""}, + map[string]interface{}{"aab": "", "bba": "", "cca": ""}, + map[string]interface{}{"aac": "", "bbc": "", "ccb": ""}, + }, + key: "ddd", + }, + {name: "no array", + key: "aaa", + }, + {name: "no keys", + input: []interface{}{map[string]interface{}{}}, + key: "aaa", + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.output, keyExists(test.input, test.key), test.name) + }) + } +} + func Test_splitStringOfSettings(t *testing.T) { testData := []struct { Input string From 0304fcc85d81977933d7eb615e5db1a6a85a3912 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 24 Mar 2023 11:21:02 +0000 Subject: [PATCH 116/191] feat: check if the Qemu guest has pending changes, and reboot if allowed --- proxmox/config_guest.go | 37 +++++++++++++++++++++++++++++++++ proxmox/config_qemu.go | 46 +++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 proxmox/config_guest.go diff --git a/proxmox/config_guest.go b/proxmox/config_guest.go new file mode 100644 index 00000000..fc5a0cc8 --- /dev/null +++ b/proxmox/config_guest.go @@ -0,0 +1,37 @@ +package proxmox + +import ( + "strconv" +) + +// All code LXC and Qemu have in common should be placed here. + +// Check if there are any pending changes that require a reboot to be applied. +func GuestHasPendingChanges(vmr *VmRef, client *Client) (bool, error) { + params, err := pendingGuestConfigFromApi(vmr, client) + if err != nil { + return false, err + } + return keyExists(params, "pending"), nil +} + +// Reboot the specified guest +func GuestReboot(vmr *VmRef, client *Client) (err error) { + _, err = client.ShutdownVm(vmr) + if err != nil { + return + } + _, err = client.StartVm(vmr) + return +} + +func pendingGuestConfigFromApi(vmr *VmRef, client *Client) ([]interface{}, error) { + err := vmr.nilCheck() + if err != nil { + return nil, err + } + if err = client.CheckVmRef(vmr); err != nil { + return nil, err + } + return client.GetItemConfigInterfaceArray("/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/pending", "Guest", "PENDING CONFIG") +} diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 6805c95a..df835b1c 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -88,8 +88,9 @@ type ConfigQemu struct { } // Create - Tell Proxmox API to make the VM -func (config ConfigQemu) Create(vmr *VmRef, client *Client) error { - return config.SetAdvanced(nil, vmr, client) +func (config ConfigQemu) Create(vmr *VmRef, client *Client) (err error) { + _, err = config.SetAdvanced(nil, false, vmr, client) + return } // DEPRECATED use ConfigQemu{}.Create Instead. @@ -677,12 +678,12 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error return &config, nil } -func (newConfig ConfigQemu) Update(vmr *VmRef, client *Client) (err error) { +func (newConfig ConfigQemu) Update(rebootIfNeeded bool, vmr *VmRef, client *Client) (rebootRequired bool, err error) { currentConfig, err := NewConfigQemuFromApi(vmr, client) if err != nil { return } - return newConfig.SetAdvanced(currentConfig, vmr, client) + return newConfig.SetAdvanced(currentConfig, rebootIfNeeded, vmr, client) } func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) { @@ -697,7 +698,7 @@ func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) { return } -func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, client *Client) (err error) { +func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeeded bool, vmr *VmRef, client *Client) (rebootRequired bool, err error) { err = newConfig.setVmr(vmr) if err != nil { return @@ -730,6 +731,19 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, c } // Moving disks changes the disk id. we need to get the config again if any disk was moved if len(markedDisks.Move) != 0 { + // We also need to check if there are pending changes + rebootRequired, err = GuestHasPendingChanges(vmr, client) + if err != nil { + return + } + if rebootRequired && rebootIfNeeded { + if err = GuestReboot(vmr, client); err != nil { + return + } + rebootRequired = false + } else { + return true, fmt.Errorf("unable to proceed with configuring vm: %d, a reboot is required", vmr.vmId) + } currentConfig, err = NewConfigQemuFromApi(vmr, client) if err != nil { return @@ -752,6 +766,21 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, c return } exitStatus, err = client.PutWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/config") + if err != nil { + return false, fmt.Errorf("error updating VM: %v, error status: %s (params: %v)", err, exitStatus, params) + } + + rebootRequired, err = GuestHasPendingChanges(vmr, client) + if err != nil { + return + } + + if rebootRequired && rebootIfNeeded { + if err = GuestReboot(vmr, client); err != nil { + return + } + rebootRequired = false + } } else { // Create @@ -760,10 +789,9 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, vmr *VmRef, c return } exitStatus, err = client.CreateQemuVm(vmr.node, params) - } - - if err != nil { - return fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) + if err != nil { + return false, fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) + } } _, err = client.UpdateVMHA(vmr, newConfig.HaState, newConfig.HaGroup) From 9bc03938ed907ebc0e4268f6c3b5e42e47b1c464 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 24 Mar 2023 11:42:19 +0000 Subject: [PATCH 117/191] refactor: disks can be enlarged while QemuGuest is live --- proxmox/config_qemu.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index df835b1c..12a97b6f 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -731,19 +731,6 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeede } // Moving disks changes the disk id. we need to get the config again if any disk was moved if len(markedDisks.Move) != 0 { - // We also need to check if there are pending changes - rebootRequired, err = GuestHasPendingChanges(vmr, client) - if err != nil { - return - } - if rebootRequired && rebootIfNeeded { - if err = GuestReboot(vmr, client); err != nil { - return - } - rebootRequired = false - } else { - return true, fmt.Errorf("unable to proceed with configuring vm: %d, a reboot is required", vmr.vmId) - } currentConfig, err = NewConfigQemuFromApi(vmr, client) if err != nil { return From 54467a697ec9b6a6798829d1861a5939afb34f97 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 24 Mar 2023 11:53:08 +0000 Subject: [PATCH 118/191] Add TODO for CloudInit and basic logic --- proxmox/config_qemu.go | 18 ++++++++++-------- proxmox/config_qemu_test.go | 4 +++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 12a97b6f..0c4d1a23 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -105,7 +105,7 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { if err != nil { return } - params, err := config.mapToApiValues(ConfigQemu{}) + _, params, err := config.mapToApiValues(ConfigQemu{}) if err != nil { return } @@ -190,8 +190,8 @@ func (config *ConfigQemu) defaults() { } -func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (params map[string]interface{}, err error) { - +func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (rebootRequired bool, params map[string]interface{}, err error) { + // TODO check if cloudInit settings changed, they require a reboot to take effect. var itemsToDelete string params = map[string]interface{}{} @@ -748,7 +748,7 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeede vmr.SetNode(newConfig.Node) } - params, err = newConfig.mapToApiValues(*currentConfig) + rebootRequired, params, err = newConfig.mapToApiValues(*currentConfig) if err != nil { return } @@ -757,9 +757,11 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeede return false, fmt.Errorf("error updating VM: %v, error status: %s (params: %v)", err, exitStatus, params) } - rebootRequired, err = GuestHasPendingChanges(vmr, client) - if err != nil { - return + if !rebootRequired { + rebootRequired, err = GuestHasPendingChanges(vmr, client) + if err != nil { + return + } } if rebootRequired && rebootIfNeeded { @@ -771,7 +773,7 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeede } else { // Create - params, err = newConfig.mapToApiValues(ConfigQemu{}) + _, params, err = newConfig.mapToApiValues(ConfigQemu{}) if err != nil { return } diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 8f653729..1b9bff94 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -28,6 +28,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { name string config *ConfigQemu currentConfig ConfigQemu + reboot bool vmr *VmRef output map[string]interface{} }{ @@ -1794,8 +1795,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(*testing.T) { - tmpParams, _ := test.config.mapToApiValues(test.currentConfig) + reboot, tmpParams, _ := test.config.mapToApiValues(test.currentConfig) require.Equal(t, test.output, tmpParams, test.name) + require.Equal(t, test.reboot, reboot, test.name) }) } } From 36cb3b689bd73254845ba2f12b3675a6ba553fef Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sat, 25 Mar 2023 20:02:30 +0000 Subject: [PATCH 119/191] fix: panic --- proxmox/config_qemu.go | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 0c4d1a23..1efe307d 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -713,27 +713,28 @@ func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeede if currentConfig != nil { // Update - - markedDisks := newConfig.Disks.markDiskChanges(*currentConfig.Disks) - // move disk to different storage or change disk format - for _, e := range markedDisks.Move { - _, err = e.move(true, vmr, client) - if err != nil { - return + if newConfig.Disks != nil && currentConfig.Disks != nil { + markedDisks := newConfig.Disks.markDiskChanges(*currentConfig.Disks) + // move disk to different storage or change disk format + for _, e := range markedDisks.Move { + _, err = e.move(true, vmr, client) + if err != nil { + return + } } - } - // increase Disks in size - for _, e := range markedDisks.Resize { - _, err = e.resize(vmr, client) - if err != nil { - return + // increase Disks in size + for _, e := range markedDisks.Resize { + _, err = e.resize(vmr, client) + if err != nil { + return + } } - } - // Moving disks changes the disk id. we need to get the config again if any disk was moved - if len(markedDisks.Move) != 0 { - currentConfig, err = NewConfigQemuFromApi(vmr, client) - if err != nil { - return + // Moving disks changes the disk id. we need to get the config again if any disk was moved + if len(markedDisks.Move) != 0 { + currentConfig, err = NewConfigQemuFromApi(vmr, client) + if err != nil { + return + } } } From 5ee8f4276a9c6c4aa9951acbd338a0097b64ab71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Sj=C3=B6str=C3=B6m?= Date: Sun, 26 Mar 2023 15:06:02 +0200 Subject: [PATCH 120/191] Support smbios1 VM configuration --- proxmox/config_qemu.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 58d4795d..237a756d 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -73,6 +73,7 @@ type ConfigQemu struct { HaState string `json:"hastate,omitempty"` HaGroup string `json:"hagroup,omitempty"` Tags string `json:"tags,omitempty"` + Smbios1 string `json:"smbios1,omitempty"` Args string `json:"args,omitempty"` // cloud-init options @@ -698,6 +699,9 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e if _, isSet := vmConfig["sshkeys"]; isSet { config.Sshkeys, _ = url.PathUnescape(vmConfig["sshkeys"].(string)) } + if _, isSet := vmConfig["smbios1"]; isSet { + config.Smbios1 = vmConfig["smbios1"].(string) + } ipconfigNames := []string{} From af6fde359a77ee8dcdd422c063ff7e4865a27a0f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:44:49 +0000 Subject: [PATCH 121/191] feat: add support for linked clones --- proxmox/config_qemu_disk.go | 81 +++-- proxmox/config_qemu_disk_ide.go | 79 ++--- proxmox/config_qemu_disk_sata.go | 79 ++--- proxmox/config_qemu_disk_scsi.go | 91 +++--- proxmox/config_qemu_disk_virtio.go | 85 +++--- proxmox/config_qemu_test.go | 471 +++++++++++++++++++++++++++-- 6 files changed, 671 insertions(+), 215 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 57724459..5b37c4f9 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -184,15 +184,16 @@ type qemuDisk struct { Disk bool // true = disk, false = passthrough EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type - File string // Only set for Passthrough. - Format QemuDiskFormat // Only set for Disk - Id uint // Only set for Disk - IOThread bool // Only set for scsi,virtio - Number uint - ReadOnly bool // Only set for scsi,virtio - Replicate bool - Serial QemuDiskSerial - Size uint + File string // Only set for Passthrough. + Format QemuDiskFormat // Only set for Disk + Id uint // Only set for Disk + IOThread bool // Only set for scsi,virtio + LinkedClone *QemuDiskLinkedClone // Only set for Disk + Number uint + ReadOnly bool // Only set for scsi,virtio + Replicate bool + Serial QemuDiskSerial + Size uint // TODO custom type Storage string // Only set for Disk Type qemuDiskType @@ -205,14 +206,20 @@ const ( Error_QemuDisk_Storage string = "storage may not be empty" ) -func (disk qemuDisk) mapToApiValues(vmID uint, create bool) (settings string) { +func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFormat QemuDiskFormat, create bool) (settings string) { if disk.Storage != "" { if create { settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) } else { - // test:100/vm-100-disk-0.raw tmpId := strconv.Itoa(int(vmID)) - settings = disk.Storage + ":" + tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(disk.Id)) + "." + string(disk.Format) + settings = tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(disk.Id)) + "." + string(disk.Format) + // storage:100/vm-100-disk-0.raw + if disk.LinkedClone != nil && disk.Storage == currentStorage && disk.Format == currentFormat { + // storage:110/base-110-disk-1.raw/100/vm-100-disk-0.raw + tmpId = strconv.Itoa(int(disk.LinkedClone.VmId)) + settings = tmpId + "/base-" + tmpId + "-disk-" + strconv.Itoa(int(disk.LinkedClone.DiskId)) + "." + string(disk.Format) + "/" + settings + } + settings = disk.Storage + ":" + settings } } @@ -294,17 +301,33 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if settings[0][0][0:1] == "/" { disk.File = settings[0][0] } else { - // "test2:105/vm-105-disk-53.qcow2, - diskAndNumberAndFormat := strings.Split(settings[0][0], ":") - disk.Storage = diskAndNumberAndFormat[0] - if len(diskAndNumberAndFormat) == 2 { - idAndFormat := strings.Split(diskAndNumberAndFormat[1], ".") - if len(idAndFormat) == 2 { - disk.Format = QemuDiskFormat(idAndFormat[1]) - tmp := strings.Split(idAndFormat[0], "-") + // storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2, + // storage:100/vm-100-disk-0.qcow2, + diskAndPath := strings.Split(settings[0][0], ":") + disk.Storage = diskAndPath[0] + if len(diskAndPath) == 2 { + pathParts := strings.Split(diskAndPath[1], "/") + if len(pathParts) == 4 { + var tmpDiskId int + tmpVmId, _ := strconv.Atoi(pathParts[0]) + tmp := strings.Split(strings.Split(pathParts[1], ".")[0], "-") if len(tmp) > 1 { - tmpId, _ := strconv.Atoi(tmp[len(tmp)-1]) - disk.Id = uint(tmpId) + tmpDiskId, _ = strconv.Atoi(tmp[len(tmp)-1]) + } + disk.LinkedClone = &QemuDiskLinkedClone{ + VmId: uint(tmpVmId), + DiskId: uint(tmpDiskId), + } + } + if len(pathParts) > 1 { + diskNameAndFormat := strings.Split(pathParts[len(pathParts)-1], ".") + if len(diskNameAndFormat) == 2 { + disk.Format = QemuDiskFormat(diskNameAndFormat[1]) + tmp := strings.Split(diskNameAndFormat[0], "-") + if len(tmp) > 1 { + tmpDiskId, _ := strconv.Atoi(tmp[len(tmp)-1]) + disk.Id = uint(tmpDiskId) + } } } } @@ -672,6 +695,11 @@ func (id QemuDiskId) Validate() error { return errors.New(ERROR_QemuDiskId_Invalid) } +type QemuDiskLinkedClone struct { + DiskId uint `json:"disk"` + VmId uint `json:"vm"` +} + type qemuDiskMark struct { Format QemuDiskFormat Id QemuDiskId @@ -814,17 +842,18 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin if storage.Disk != nil { if currentStorage == nil || currentStorage.Disk == nil { // Create - params[string(id)] = storage.Disk.mapToApiValues(vmID, true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) return delete } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update storage.Disk.Id = currentStorage.Disk.Id - params[string(id)] = storage.Disk.mapToApiValues(vmID, false) + storage.Disk.LinkedClone = currentStorage.Disk.LinkedClone + params[string(id)] = storage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) } else { // Delete and Create // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. - params[string(id)] = storage.Disk.mapToApiValues(vmID, true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) } return delete } @@ -835,7 +864,7 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin // Passthrough if storage.Passthrough != nil { // Create or Update - params[string(id)] = storage.Passthrough.mapToApiValues(0, false) + params[string(id)] = storage.Passthrough.mapToApiValues(0, "", "", false) return delete } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index 8149eada..b7dd1eb8 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -3,36 +3,38 @@ package proxmox import "strconv" type QemuIdeDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: ide, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedClone: disk.LinkedClone, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: ide, } } @@ -219,18 +221,19 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { } if tmpDisk.File == "" { return &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedClone: tmpDisk.LinkedClone, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 6ca552b8..f0f214e0 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -3,36 +3,38 @@ package proxmox import "strconv" type QemuSataDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: sata, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedClone: disk.LinkedClone, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: sata, } } @@ -231,18 +233,19 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { } if tmpDisk.File == "" { return &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedClone: tmpDisk.LinkedClone, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuSataStorage{Passthrough: &QemuSataPassthrough{ diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 483ab68b..2cc6cb6d 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -3,40 +3,42 @@ package proxmox import "strconv" type QemuScsiDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: scsi, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedClone: disk.LinkedClone, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: scsi, } } @@ -389,20 +391,21 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { } if tmpDisk.File == "" { return &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedClone: tmpDisk.LinkedClone, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index a55f45b9..4fd8c273 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -3,38 +3,40 @@ package proxmox import "strconv" type QemuVirtIODisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: virtIO, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedClone: disk.LinkedClone, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: virtIO, } } @@ -295,19 +297,20 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { } if tmpDisk.File == "" { return &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedClone: tmpDisk.LinkedClone, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 1b9bff94..9d3521f6 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -1197,12 +1197,28 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, - Id: 23, Size: 10, Storage: "test", }}}}}, output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, + {name: "Update Disk.Ide.Disk_X.Disk CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide3": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, {name: "Update Disk.Ide.Disk_X.Disk DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{}}}}, @@ -1217,7 +1233,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"ide1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk MIGRATE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, Size: 10, Storage: "test2", }}}}}, @@ -1232,7 +1262,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide2": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk RESIZE DOWN LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, Size: 9, Storage: "test", }}}}}, @@ -1247,16 +1291,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, - Id: 23, Size: 11, Storage: "test", }}}}}, output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, + {name: "Update Disk.Ide.Disk_X.Disk RESIZE UP LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide3": "test:110/base-110-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, {name: "Update Disk.Ide.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, - output: map[string]interface{}{"ide0": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide0": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Ide.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -1267,7 +1329,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Qcow2, - Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"ide1": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Disk.Format CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Qcow2, Size: 10, Storage: "test", }}}}}, @@ -1363,12 +1439,28 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, - Id: 23, Size: 10, Storage: "test", }}}}}, output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, + {name: "Update Disk.Sata.Disk_X.Disk CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata3": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, {name: "Update Disk.Sata.Disk_X.Disk DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: sataBase}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{}}}}, @@ -1383,7 +1475,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"sata5": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk MIGRATE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, Size: 10, Storage: "test2", }}}}}, @@ -1398,7 +1504,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata0": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk RESIZE DOWN LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, Size: 9, Storage: "test", }}}}}, @@ -1413,16 +1533,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, - Id: 23, Size: 11, Storage: "test", }}}}}, output: map[string]interface{}{"sata1": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, + {name: "Update Disk.Sata.Disk_X.Disk RESIZE UP LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata1": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, {name: "Update Disk.Sata.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: sataBase}}}, - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: sataBase}}}, - output: map[string]interface{}{"sata2": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata2": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Sata.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -1433,7 +1571,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Qcow2, - Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Disk.Format CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Qcow2, Size: 10, Storage: "test", }}}}}, @@ -1529,12 +1681,28 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, - Id: 23, Size: 10, Storage: "test", }}}}}, output: map[string]interface{}{"scsi15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, + {name: "Update Disk.Scsi.Disk_X.Disk CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi15": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, {name: "Update Disk.Scsi.Disk_X.Disk DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: scsiBase}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{}}}}, @@ -1549,7 +1717,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"scsi17": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk MIGRATE Linked Clone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, Size: 10, Storage: "test2", }}}}}, @@ -1564,7 +1746,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi18": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk RESIZE DOWN LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, Size: 9, Storage: "test", }}}}}, @@ -1579,16 +1775,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, - Id: 23, Size: 11, Storage: "test", }}}}}, output: map[string]interface{}{"scsi19": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, + {name: "Update Disk.Scsi.Disk_X.Disk RESIZE UP LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi19": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, {name: "Update Disk.Scsi.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: scsiBase}}}, - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: scsiBase}}}, - output: map[string]interface{}{"scsi20": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi20": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Scsi.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -1599,7 +1813,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Qcow2, - Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"scsi21": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Disk.Format CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Qcow2, Size: 10, Storage: "test", }}}}}, @@ -1695,12 +1923,28 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, - Id: 23, Size: 10, Storage: "test", }}}}}, output: map[string]interface{}{"virtio15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, + {name: "Update Disk.VirtIO.Disk_X.Disk CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio15": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, + }, {name: "Update Disk.VirtIO.Disk_X.Disk DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: virtioBase}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}}}, @@ -1715,7 +1959,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 10, + Storage: "test2", + }}}}}, + output: map[string]interface{}{"virtio1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk MIGRATE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, + Size: 10, + Storage: "test1", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, Size: 10, Storage: "test2", }}}}}, @@ -1730,7 +1988,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, - Id: 23, + Size: 9, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio2": "test:9,backup=0,format=raw,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE DOWN LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, Size: 9, Storage: "test", }}}}}, @@ -1745,16 +2017,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, - Id: 23, Size: 11, Storage: "test", }}}}}, output: map[string]interface{}{"virtio3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, + {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE UP LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Size: 11, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio3": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + }, {name: "Update Disk.VirtIO.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: virtioBase}}}, - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: virtioBase}}}, - output: map[string]interface{}{"virtio4": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio4": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.VirtIO.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ @@ -1765,7 +2055,21 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Qcow2, - Id: 23, + Size: 10, + Storage: "test", + }}}}}, + output: map[string]interface{}{"virtio5": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Disk.Format CHANGE LinkedClone", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, + Size: 10, + Storage: "test", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Qcow2, Size: 10, Storage: "test", }}}}}, @@ -1876,6 +2180,33 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Ide Disk ALL LinkedClone", + input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_wr=15,iops_wr_max=14,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57, Concurrent: 1.46}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 12}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, Concurrent: 15}, + }, + }, + Cache: QemuDiskCache_WriteThrough, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, + Replicate: false, + Serial: "disk-9763", + Size: 1032, + Storage: "test2", + }}}}}, + }, {name: "Disks Ide Disk aio", input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,aio=io_uring"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -2287,6 +2618,33 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Sata Disk ALL LinkedClone", + input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, + }, {name: "Disks Sata Disk aio", input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,aio=native"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -2704,6 +3062,35 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, + {name: "Disks Scsi Disk ALL LinkedClone", + input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_WriteBack, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + IOThread: true, + LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test", + }}}}}, + }, {name: "Disks Scsi Disk aio", input: map[string]interface{}{"scsi2": "test:100/vm-100-disk-2.qcow2,aio=threads"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -3158,6 +3545,34 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks VirtIO Disk ALL LinkedClone", + input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + Data: QemuDiskBandwidthData{ + ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + }, + }, + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + IOThread: true, + LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, + }, {name: "Disks VirtIO Disk aio", input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,aio=io_uring"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ From 38194b5b2b11062d43f284465727b0477f8685c8 Mon Sep 17 00:00:00 2001 From: mleone87 <807457+mleone87@users.noreply.github.com> Date: Tue, 28 Mar 2023 23:43:45 +0200 Subject: [PATCH 122/191] Update config_qemu.go --- proxmox/config_qemu.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 237a756d..6ddac61a 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -449,6 +449,9 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { if config.Nameserver != "" { configParams["nameserver"] = config.Nameserver } + if config.Smbios1 != "" { + configParams["smbios1"] = config.Smbios1 + } if config.Sshkeys != "" { configParams["sshkeys"] = sshKeyUrlEncode(config.Sshkeys) } From b287d45fd69716f45f3505d3fa7531265fdddc06 Mon Sep 17 00:00:00 2001 From: Tobias Mollstam Date: Wed, 29 Mar 2023 11:45:32 +0200 Subject: [PATCH 123/191] Don't include large req/resp bodies (>5 Mb) in debug output --- proxmox/session.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/proxmox/session.go b/proxmox/session.go index 057d6c06..b9b3a3dd 100644 --- a/proxmox/session.go +++ b/proxmox/session.go @@ -17,6 +17,8 @@ import ( var Debug = new(bool) +const DebugLargeBodyThreshold = 5 * 1024 * 1024 + type Response struct { Resp *http.Response Body []byte @@ -217,7 +219,11 @@ func (s *Session) Do(req *http.Request) (*http.Response, error) { } if *Debug { - d, _ := httputil.DumpRequestOut(req, true) + includeBody := req.ContentLength < DebugLargeBodyThreshold + d, _ := httputil.DumpRequestOut(req, includeBody) + if !includeBody { + d = append(d, fmt.Sprintf("\n\n", req.ContentLength)...) + } log.Printf(">>>>>>>>>> REQUEST:\n%v", string(d)) } @@ -238,7 +244,11 @@ func (s *Session) Do(req *http.Request) (*http.Response, error) { resp.Body = io.NopCloser(bytes.NewReader(respBody)) if *Debug { - dr, _ := httputil.DumpResponse(resp, true) + includeBody := resp.ContentLength < DebugLargeBodyThreshold + dr, _ := httputil.DumpResponse(resp, includeBody) + if !includeBody { + dr = append(dr, fmt.Sprintf("\n\n", resp.ContentLength)...) + } log.Printf("<<<<<<<<<< RESULT:\n%v", string(dr)) } From 56d99519d14ca47bc84d22c760dd0ac535ddce77 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:58:57 +0000 Subject: [PATCH 124/191] refactor: remove unused option --- proxmox/config_qemu_disk.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 5b37c4f9..feed3f62 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -189,8 +189,7 @@ type qemuDisk struct { Id uint // Only set for Disk IOThread bool // Only set for scsi,virtio LinkedClone *QemuDiskLinkedClone // Only set for Disk - Number uint - ReadOnly bool // Only set for scsi,virtio + ReadOnly bool // Only set for scsi,virtio Replicate bool Serial QemuDiskSerial Size uint From 0de34f70b21eb8304e7bbaa621c02e45f431e2d0 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 2 Apr 2023 18:36:14 +0000 Subject: [PATCH 125/191] fix: disks get updated when nothing changes disks getting updated when nothing changes, adds the current state to the pending state. --- proxmox/config_qemu_disk.go | 44 ++++++++++--- proxmox/config_qemu_test.go | 120 ++++++++++++++++++++++++++++++------ 2 files changed, 135 insertions(+), 29 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index feed3f62..7579e125 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -821,8 +821,16 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin } // CDROM if storage.CdRom != nil { - // Create or Update - params[string(id)] = storage.CdRom.mapToApiValues() + if currentStorage == nil || currentStorage.CdRom == nil { + // Create + params[string(id)] = storage.CdRom.mapToApiValues() + } else { + // Update + cdRom := storage.CdRom.mapToApiValues() + if cdRom != currentStorage.CdRom.mapToApiValues() { + params[string(id)] = cdRom + } + } return delete } else if currentStorage != nil && currentStorage.CdRom != nil && storage.CloudInit == nil && storage.Disk == nil && storage.Passthrough == nil { // Delete @@ -830,8 +838,16 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin } // CloudInit if storage.CloudInit != nil { - // Create or Update - params[string(id)] = storage.CloudInit.mapToApiValues() + if currentStorage == nil || currentStorage.CloudInit == nil { + // Create + params[string(id)] = storage.CloudInit.mapToApiValues() + } else { + // Update + cloudInit := storage.CloudInit.mapToApiValues() + if cloudInit != currentStorage.CloudInit.mapToApiValues() { + params[string(id)] = cloudInit + } + } return delete } else if currentStorage != nil && currentStorage.CloudInit != nil && storage.Disk == nil && storage.Passthrough == nil { // Delete @@ -842,28 +858,38 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin if currentStorage == nil || currentStorage.Disk == nil { // Create params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) - return delete } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update storage.Disk.Id = currentStorage.Disk.Id storage.Disk.LinkedClone = currentStorage.Disk.LinkedClone - params[string(id)] = storage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) + disk := storage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) + if disk != currentStorage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) { + params[string(id)] = disk + } } else { // Delete and Create // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) } - return delete } + return delete } else if currentStorage != nil && currentStorage.Disk != nil && storage.Passthrough == nil { // Delete return AddToList(delete, string(id)) } // Passthrough if storage.Passthrough != nil { - // Create or Update - params[string(id)] = storage.Passthrough.mapToApiValues(0, "", "", false) + if currentStorage == nil || currentStorage.Passthrough == nil { + // Create + params[string(id)] = storage.Passthrough.mapToApiValues(0, "", "", false) + } else { + // Update + passthrough := storage.Passthrough.mapToApiValues(0, "", "", false) + if passthrough != currentStorage.Passthrough.mapToApiValues(0, "", "", false) { + params[string(id)] = passthrough + } + } return delete } else if currentStorage != nil && currentStorage.Passthrough != nil { // Delete diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 9d3521f6..c091c125 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -1152,7 +1152,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Ide.Disk_X.CdRom SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, - output: map[string]interface{}{"ide0": "cdrom,media=cdrom"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.CdRom.Iso.File CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, @@ -1173,7 +1173,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Ide.Disk_X.CloudInit SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: update_CloudInit}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{CloudInit: update_CloudInit}}}}, - output: map[string]interface{}{"ide0": "test:cloudinit,format=raw"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.CloudInit.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, @@ -1294,7 +1294,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.Disk RESIZE UP LinkedClone", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -1309,7 +1309,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"ide3": "test:110/base-110-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: ideBase}}}, @@ -1318,7 +1318,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 10, Storage: "test", }}}}}, - output: map[string]interface{}{"ide0": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -1349,6 +1349,26 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, output: map[string]interface{}{"ide1": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, + // Update Disk.Ide.Disk_X.Passthrough + {name: "Update Disk.Ide.Disk_X.Passthrough CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{"ide0": "/dev/disk/sda,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Ide.Disk_X.Passthrough SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{}, + }, // Update Disk.Sata {name: "Update Disk.Sata.Disk_X DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{}}}}, @@ -1394,7 +1414,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Sata.Disk_X.CdRom SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, - output: map[string]interface{}{"sata2": "cdrom,media=cdrom"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.CdRom.Iso.File CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, @@ -1415,7 +1435,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Sata.Disk_X.CloudInit SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: update_CloudInit}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CloudInit: update_CloudInit}}}}, - output: map[string]interface{}{"sata0": "test:cloudinit,format=raw"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.CloudInit.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, @@ -1536,7 +1556,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"sata1": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.Disk RESIZE UP LinkedClone", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -1551,7 +1571,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"sata1": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: sataBase}}}, @@ -1560,7 +1580,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 10, Storage: "test", }}}}}, - output: map[string]interface{}{"sata2": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -1591,6 +1611,26 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, + // Update Disk.Sata.Disk_X.Passthrough + {name: "Update Disk.Sata.Disk_X.Passthrough CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{"sata0": "/dev/disk/sda,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Sata.Disk_X.Passthrough SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{}, + }, // Update Disk.Scsi {name: "Update Disk.Scsi.Disk_X DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{}}}}, @@ -1636,7 +1676,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Scsi.Disk_X.CdRom SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, - output: map[string]interface{}{"scsi8": "cdrom,media=cdrom"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.CdRom.Iso.File CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, @@ -1657,7 +1697,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.Scsi.Disk_X.CloudInit SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{CloudInit: update_CloudInit}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{CloudInit: update_CloudInit}}}}, - output: map[string]interface{}{"scsi12": "test:cloudinit,format=raw"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.CloudInit.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, @@ -1778,7 +1818,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"scsi19": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.Disk RESIZE UP LinkedClone", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -1793,7 +1833,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"scsi19": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_20: scsiBase}}}, @@ -1802,7 +1842,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 10, Storage: "test", }}}}}, - output: map[string]interface{}{"scsi20": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -1833,6 +1873,26 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, output: map[string]interface{}{"scsi21": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, + // Update Disk.Scsi.Disk_X.Passthrough + {name: "Update Disk.Scsi.Disk_X.Passthrough CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{"scsi0": "/dev/disk/sda,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.Scsi.Disk_X.Passthrough SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{}, + }, // Update Disk.VirtIO {name: "Update Disk.VirtIO.Disk_X DELETE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{}}}}, @@ -1878,7 +1938,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.VirtIO.Disk_X.CdRom SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{CdRom: &QemuCdRom{Passthrough: true}}}}}, - output: map[string]interface{}{"virtio8": "cdrom,media=cdrom"}, + output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.CdRom.Iso.File CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{CdRom: &QemuCdRom{Iso: &IsoFile{File: "test.iso", Storage: "Test"}}}}}}, @@ -1899,7 +1959,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { {name: "Update Disk.VirtIO.Disk_X.CloudInit SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{CloudInit: update_CloudInit}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{CloudInit: update_CloudInit}}}}, - output: map[string]interface{}{"virtio12": "test:cloudinit,format=raw"}, + output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.CloudInit.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{CloudInit: &QemuCloudInitDisk{Format: format_Raw, Storage: "Test"}}}}}, @@ -2020,7 +2080,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"virtio3": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE UP LinkedClone", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ @@ -2035,7 +2095,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 11, Storage: "test", }}}}}, - output: map[string]interface{}{"virtio3": "test:100/base-100-disk-1.raw/0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.Disk SAME", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: virtioBase}}}, @@ -2044,7 +2104,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 10, Storage: "test", }}}}}, - output: map[string]interface{}{"virtio4": "test:0/vm-0-disk-23.raw,backup=0,replicate=0"}, + output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.Disk.Format CHANGE", currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ @@ -2075,6 +2135,26 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { }}}}}, output: map[string]interface{}{"virtio5": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, + // Update Disk.VirtIO.Disk_X.Passthrough + {name: "Update Disk.VirtIO.Disk_X.Passthrough CHANGE", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + AsyncIO: QemuDiskAsyncIO_Native, + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{"virtio0": "/dev/disk/sda,aio=native,backup=0,replicate=0"}, + }, + {name: "Update Disk.VirtIO.Disk_X.Passthrough SAME", + currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + File: "/dev/disk/sda", + }}}}}, + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + File: "/dev/disk/sda", + }}}}}, + output: map[string]interface{}{}, + }, // Update Iso {name: "Update Iso nil", currentConfig: ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, From d5c4ec3cb93132dafdb688a5079c36febe2dbccc Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 3 Apr 2023 09:34:50 +0000 Subject: [PATCH 126/191] feat: Add setting for iops burst duration --- proxmox/config_qemu_disk.go | 29 ++- proxmox/config_qemu_test.go | 392 ++++++++++++++++++++++++++++-------- 2 files changed, 335 insertions(+), 86 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 7579e125..2fe6bdf7 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -205,6 +205,7 @@ const ( Error_QemuDisk_Storage string = "storage may not be empty" ) +// Maps all the disk related settings to api values proxmox understands. func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFormat QemuDiskFormat, create bool) (settings string) { if disk.Storage != "" { if create { @@ -250,12 +251,19 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor if disk.Bandwidth.Iops.ReadLimit.Burst != 0 { settings = settings + ",iops_rd_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.Burst)) } + if disk.Bandwidth.Iops.ReadLimit.BurstDuration != 0 { + settings = settings + ",iops_rd_max_length=" + strconv.Itoa(int(disk.Bandwidth.Iops.ReadLimit.BurstDuration)) + } + if disk.Bandwidth.Iops.WriteLimit.Concurrent != 0 { settings = settings + ",iops_wr=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Concurrent)) } if disk.Bandwidth.Iops.WriteLimit.Burst != 0 { settings = settings + ",iops_wr_max=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.Burst)) } + if disk.Bandwidth.Iops.WriteLimit.BurstDuration != 0 { + settings = settings + ",iops_wr_max_length=" + strconv.Itoa(int(disk.Bandwidth.Iops.WriteLimit.BurstDuration)) + } if (disk.Type == scsi || disk.Type == virtIO) && disk.IOThread { settings = settings + ",iothread=1" @@ -267,6 +275,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor if disk.Bandwidth.Data.ReadLimit.Burst != 0 { settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.Data.ReadLimit.Burst) } + if disk.Bandwidth.Data.WriteLimit.Concurrent != 0 { settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.Data.WriteLimit.Concurrent) } @@ -290,7 +299,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor return } -// Maps all the disk related settings +// Maps all the disk related settings to our own data structure. func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(settings) == 0 { return nil @@ -362,6 +371,10 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { tmp, _ := strconv.Atoi(e[1]) disk.Bandwidth.Iops.ReadLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) } + if e[0] == "iops_rd_max_length" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.Iops.ReadLimit.BurstDuration = QemuDiskBandwidthBurstDuration(tmp) + } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) disk.Bandwidth.Iops.WriteLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) @@ -370,6 +383,10 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { tmp, _ := strconv.Atoi(e[1]) disk.Bandwidth.Iops.WriteLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) } + if e[0] == "iops_wr_max_length" { + tmp, _ := strconv.Atoi(e[1]) + disk.Bandwidth.Iops.WriteLimit.BurstDuration = QemuDiskBandwidthBurstDuration(tmp) + } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) continue @@ -483,6 +500,9 @@ func (bandwidth QemuDiskBandwidth) Validate() error { return bandwidth.Iops.Validate() } +// burst duration in seconds +type QemuDiskBandwidthBurstDuration uint + type QemuDiskBandwidthData struct { ReadLimit QemuDiskBandwidthDataLimit `json:"read,omitempty"` WriteLimit QemuDiskBandwidthDataLimit `json:"write,omitempty"` @@ -497,7 +517,7 @@ func (data QemuDiskBandwidthData) Validate() error { } type QemuDiskBandwidthDataLimit struct { - Burst QemuDiskBandwidthDataLimitBurst `json:"burst,omitempty"` // 0 = default + Burst QemuDiskBandwidthDataLimitBurst `json:"burst,omitempty"` // 0 = unlimited Concurrent QemuDiskBandwidthDataLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } @@ -549,8 +569,9 @@ func (iops QemuDiskBandwidthIops) Validate() error { } type QemuDiskBandwidthIopsLimit struct { - Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = default - Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited + Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = unlimited + BurstDuration QemuDiskBandwidthBurstDuration `json:"burst_duration,omitempty"` + Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index c091c125..2755ca46 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -58,12 +58,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_DirectSync, @@ -75,7 +75,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 32, Storage: "Test", }}}}}, - output: map[string]interface{}{"ide0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=558485ef-478,ssd=1"}, + output: map[string]interface{}{"ide0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=558485ef-478,ssd=1"}, }, {name: "Create Disks.Ide.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -129,6 +129,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"ide2": ",backup=0,iops_rd=34,replicate=0"}, @@ -141,6 +145,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, @@ -184,12 +192,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_Unsafe, @@ -199,7 +207,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Replicate: true, Serial: "test-serial_757465-gdg", }}}}}, - output: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + output: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, }, {name: "Create Disks.Ide.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -253,6 +261,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"ide2": ",backup=0,iops_rd=34,replicate=0"}, @@ -265,6 +277,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, @@ -317,12 +333,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_Unsafe, @@ -334,7 +350,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 32, Storage: "Test", }}}}}, - output: map[string]interface{}{"sata0": "Test:32,aio=native,cache=unsafe,discard=on,format=qcow2,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=ab_C-12_3,ssd=1"}, + output: map[string]interface{}{"sata0": "Test:32,aio=native,cache=unsafe,discard=on,format=qcow2,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=ab_C-12_3,ssd=1"}, }, {name: "Create Disks.Sata.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -388,6 +404,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"sata0": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"sata1": ",backup=0,iops_rd=34,replicate=0"}, @@ -400,6 +420,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"sata3": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"sata4": ",backup=0,iops_wr=23,replicate=0"}, @@ -443,12 +467,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_Unsafe, @@ -458,7 +482,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Replicate: true, Serial: "test-serial_757465-gdg", }}}}}, - output: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + output: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, }, {name: "Create Disks.Sata.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -512,6 +536,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"sata1": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"sata2": ",backup=0,iops_rd=34,replicate=0"}, @@ -524,6 +552,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"sata4": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"sata5": ",backup=0,iops_wr=23,replicate=0"}, @@ -576,12 +608,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_DirectSync, @@ -595,7 +627,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 32, Storage: "Test", }}}}}, - output: map[string]interface{}{"scsi0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,ssd=1"}, + output: map[string]interface{}{"scsi0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,ssd=1"}, }, {name: "Create Disks.Scsi.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -649,6 +681,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"scsi14": ",backup=0,iops_rd=34,replicate=0"}, @@ -661,6 +697,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, @@ -712,12 +752,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_Unsafe, @@ -729,7 +769,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Replicate: true, Serial: "test-serial_757465-gdg", }}}}}, - output: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,ssd=1"}, + output: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,ssd=1"}, }, {name: "Create Disks.Scsi.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -783,6 +823,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"scsi13": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"scsi14": ",backup=0,iops_rd=34,replicate=0"}, @@ -795,6 +839,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"scsi16": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, @@ -855,12 +903,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_DirectSync, @@ -873,7 +921,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Size: 32, Storage: "Test", }}}}}, - output: map[string]interface{}{"virtio0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478"}, + output: map[string]interface{}{"virtio0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478"}, }, {name: "Create Disks.VirtIO.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -899,6 +947,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 1}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max_length=1,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"virtio7": ",backup=0,iops_rd=34,replicate=0"}, @@ -911,6 +963,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max_length=2,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"virtio10": ",backup=0,iops_wr=23,replicate=0"}, @@ -927,6 +983,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"virtio14": ",backup=0,iops_rd=34,replicate=0"}, @@ -939,6 +999,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, @@ -986,12 +1050,12 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Backup: true, Bandwidth: QemuDiskBandwidth{ Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10, Burst: float99}, - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45, Burst: float79}, + ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34, Burst: uint78}, - WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23, Burst: uint89}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, Cache: QemuDiskCache_Unsafe, @@ -1002,7 +1066,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { Replicate: true, Serial: "test-serial_757465-gdg", }}}}}, - output: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_wr=23,iops_wr_max=89,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg"}, + output: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg"}, }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -1056,6 +1120,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max=78,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}}}}}}, + output: map[string]interface{}{"virtio13": ",backup=0,iops_rd_max_length=3,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.ReadLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, output: map[string]interface{}{"virtio14": ",backup=0,iops_rd=34,replicate=0"}, @@ -1068,6 +1136,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max=89,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 4}}}}}}}}, + output: map[string]interface{}{"virtio0": ",backup=0,iops_wr_max_length=4,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops.WriteLimit.Concurrent", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, @@ -2235,7 +2307,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Ide Disk ALL", - input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_wr=15,iops_wr_max=14,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -2245,8 +2317,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 12}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, Concurrent: 15}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, }, }, Cache: QemuDiskCache_WriteThrough, @@ -2261,7 +2333,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Ide Disk ALL LinkedClone", - input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_wr=15,iops_wr_max=14,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -2271,8 +2343,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 12}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, Concurrent: 15}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, }, }, Cache: QemuDiskCache_WriteThrough, @@ -2352,6 +2424,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Ide Disk iops_rd_max_length", + input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, {name: "Disks Ide Disk iops_wr", input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,iops_wr=15"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -2374,6 +2457,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Ide Disk iops_wr_max_length", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + Replicate: true, + Storage: "test2", + }}}}}, + }, {name: "Disks Ide Disk mbps_rd", input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,mbps_rd=1.46"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -2471,7 +2565,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Ide Passthrough All", - input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -2481,8 +2575,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_Unsafe, @@ -2547,6 +2641,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Ide Passthrough iops_rd_max_length", + input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Ide Passthrough iops_wr", input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ @@ -2565,6 +2668,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Ide Passthrough iops_wr_max_length", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Ide Passthrough mbps_rd", input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ @@ -2673,7 +2785,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Sata Disk ALL", - input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ AsyncIO: QemuDiskAsyncIO_Native, Backup: false, @@ -2683,8 +2795,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_None, @@ -2699,7 +2811,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Sata Disk ALL LinkedClone", - input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ AsyncIO: QemuDiskAsyncIO_Native, Backup: false, @@ -2709,8 +2821,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_None, @@ -2790,6 +2902,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Sata Disk iops_rd_max_length", + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, {name: "Disks Sata Disk iops_wr", input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -2812,6 +2935,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Sata Disk iops_wr_max_length", + input: map[string]interface{}{"sata3": "test2:100/vm-100-disk-47.qcow2,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + Replicate: true, + Storage: "test2", + }}}}}, + }, {name: "Disks Sata Disk mbps_rd", input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -2913,7 +3047,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Sata Passthrough All", - input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=5,iops_wr=11,iops_wr_max=13,iops_wr_max_length=4,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -2923,8 +3057,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 5, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 11}, }, }, Cache: QemuDiskCache_DirectSync, @@ -2989,6 +3123,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Sata Passthrough iops_rd_max_length", + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Sata Passthrough iops_wr", input: map[string]interface{}{"sata2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ @@ -3007,6 +3150,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Sata Passthrough iops_wr_max_length", + input: map[string]interface{}{"sata3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Sata Passthrough mbps_rd", input: map[string]interface{}{"sata4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ @@ -3115,7 +3267,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Scsi Disk ALL", - input: map[string]interface{}{"scsi1": "test:100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"scsi1": "test:100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -3125,8 +3277,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_WriteBack, @@ -3143,7 +3295,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Scsi Disk ALL LinkedClone", - input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -3153,8 +3305,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_WriteBack, @@ -3236,6 +3388,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, + {name: "Disks Scsi Disk iops_rd_max_length", + input: map[string]interface{}{"scsi7": "test:100/vm-100-disk-2.qcow2,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, {name: "Disks Scsi Disk iops_wr", input: map[string]interface{}{"scsi8": "test:100/vm-100-disk-2.qcow2,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -3258,6 +3421,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, + {name: "Disks Scsi Disk iops_wr_max_length", + input: map[string]interface{}{"scsi9": "test:100/vm-100-disk-2.qcow2,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + Replicate: true, + Storage: "test", + }}}}}, + }, {name: "Disks Scsi Disk iothread", input: map[string]interface{}{"scsi10": "test:100/vm-100-disk-2.qcow2,iothread=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -3377,7 +3551,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Scsi Passthrough All", - input: map[string]interface{}{"scsi1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"scsi1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -3387,8 +3561,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_None, @@ -3455,6 +3629,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Scsi Passthrough iops_rd_max_length", + input: map[string]interface{}{"scsi7": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Scsi Passthrough iops_wr", input: map[string]interface{}{"scsi8": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ @@ -3473,6 +3656,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Scsi Passthrough iops_wr_max_length", + input: map[string]interface{}{"scsi9": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks Scsi Passthrough iothread", input: map[string]interface{}{"scsi10": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iothread=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ @@ -3599,7 +3791,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks VirtIO Disk ALL", - input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -3609,8 +3801,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, }, }, Cache: QemuDiskCache_DirectSync, @@ -3626,7 +3818,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks VirtIO Disk ALL LinkedClone", - input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -3636,8 +3828,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, }, }, Cache: QemuDiskCache_DirectSync, @@ -3710,12 +3902,19 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { {name: "Disks VirtIO Disk iops_rd_max", input: map[string]interface{}{"virtio7": "test2:100/vm-100-disk-31.qcow2,iops_rd_max=12"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - Backup: true, - Bandwidth: QemuDiskBandwidth{ - Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}, - }, - }, + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, + {name: "Disks VirtIO Disk iops_rd_max_length", + input: map[string]interface{}{"virtio7": "test2:100/vm-100-disk-31.qcow2,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, Format: QemuDiskFormat_Qcow2, Id: uint31, Replicate: true, @@ -3744,6 +3943,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks VirtIO Disk iops_wr_max_length", + input: map[string]interface{}{"virtio9": "test2:100/vm-100-disk-31.qcow2,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + Replicate: true, + Storage: "test2", + }}}}}, + }, {name: "Disks VirtIO Disk iothread", input: map[string]interface{}{"virtio10": "test2:100/vm-100-disk-31.qcow2,iothread=1"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ @@ -3856,7 +4066,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks VirtIO Passthrough ALL", - input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_wr=11,iops_wr_max=13,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G"}, + input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ AsyncIO: QemuDiskAsyncIO_Native, Backup: false, @@ -3866,8 +4076,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, Concurrent: 11}, + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, Cache: QemuDiskCache_Unsafe, @@ -3933,6 +4143,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks VirtIO Passthrough iops_rd_max_length", + input: map[string]interface{}{"virtio7": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_rd_max_length=2"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks VirtIO Passthrough iops_wr", input: map[string]interface{}{"virtio8": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr=11"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ @@ -3951,6 +4170,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks VirtIO Passthrough iops_wr_max_length", + input: map[string]interface{}{"virtio9": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iops_wr_max_length=3"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 3}}}, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + }}}}}, + }, {name: "Disks VirtIO Passthrough iothread", input: map[string]interface{}{"virtio10": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,iothread=1"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ From 72653078f2d15ace2175d73112f0d5c69c1833a9 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 3 Apr 2023 10:06:55 +0000 Subject: [PATCH 127/191] refactor: rename `Data` to `MBps` --- proxmox/config_qemu_disk.go | 118 ++-- proxmox/config_qemu_disk_test.go | 174 +++--- proxmox/config_qemu_test.go | 932 +++++++++++++++---------------- 3 files changed, 612 insertions(+), 612 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 2fe6bdf7..faef43e5 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -269,18 +269,18 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor settings = settings + ",iothread=1" } - if disk.Bandwidth.Data.ReadLimit.Concurrent != 0 { - settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.Data.ReadLimit.Concurrent) + if disk.Bandwidth.MBps.ReadLimit.Concurrent != 0 { + settings = settings + fmt.Sprintf(",mbps_rd=%.2f", disk.Bandwidth.MBps.ReadLimit.Concurrent) } - if disk.Bandwidth.Data.ReadLimit.Burst != 0 { - settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.Data.ReadLimit.Burst) + if disk.Bandwidth.MBps.ReadLimit.Burst != 0 { + settings = settings + fmt.Sprintf(",mbps_rd_max=%.2f", disk.Bandwidth.MBps.ReadLimit.Burst) } - if disk.Bandwidth.Data.WriteLimit.Concurrent != 0 { - settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.Data.WriteLimit.Concurrent) + if disk.Bandwidth.MBps.WriteLimit.Concurrent != 0 { + settings = settings + fmt.Sprintf(",mbps_wr=%.2f", disk.Bandwidth.MBps.WriteLimit.Concurrent) } - if disk.Bandwidth.Data.WriteLimit.Burst != 0 { - settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.Data.WriteLimit.Burst) + if disk.Bandwidth.MBps.WriteLimit.Burst != 0 { + settings = settings + fmt.Sprintf(",mbps_wr_max=%.2f", disk.Bandwidth.MBps.WriteLimit.Burst) } if !disk.Replicate { @@ -393,19 +393,19 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { } if e[0] == "mbps_rd" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Concurrent = QemuDiskBandwidthDataLimitConcurrent(math.Round(tmp*100) / 100) + disk.Bandwidth.MBps.ReadLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) } if e[0] == "mbps_rd_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.ReadLimit.Burst = QemuDiskBandwidthDataLimitBurst(math.Round(tmp*100) / 100) + disk.Bandwidth.MBps.ReadLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Concurrent = QemuDiskBandwidthDataLimitConcurrent(math.Round(tmp*100) / 100) + disk.Bandwidth.MBps.WriteLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) } if e[0] == "mbps_wr_max" { tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.Data.WriteLimit.Burst = QemuDiskBandwidthDataLimitBurst(math.Round(tmp*100) / 100) + disk.Bandwidth.MBps.WriteLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) } if e[0] == "replicate" { disk.Replicate, _ = strconv.ParseBool(e[1]) @@ -488,12 +488,12 @@ func (asyncIO QemuDiskAsyncIO) Validate() error { } type QemuDiskBandwidth struct { - Data QemuDiskBandwidthData `json:"data,omitempty"` + MBps QemuDiskBandwidthMBps `json:"mbps,omitempty"` Iops QemuDiskBandwidthIops `json:"iops,omitempty"` } func (bandwidth QemuDiskBandwidth) Validate() error { - err := bandwidth.Data.Validate() + err := bandwidth.MBps.Validate() if err != nil { return err } @@ -503,25 +503,26 @@ func (bandwidth QemuDiskBandwidth) Validate() error { // burst duration in seconds type QemuDiskBandwidthBurstDuration uint -type QemuDiskBandwidthData struct { - ReadLimit QemuDiskBandwidthDataLimit `json:"read,omitempty"` - WriteLimit QemuDiskBandwidthDataLimit `json:"write,omitempty"` +type QemuDiskBandwidthIops struct { + ReadLimit QemuDiskBandwidthIopsLimit `json:"read,omitempty"` + WriteLimit QemuDiskBandwidthIopsLimit `json:"write,omitempty"` } -func (data QemuDiskBandwidthData) Validate() error { - err := data.ReadLimit.Validate() +func (iops QemuDiskBandwidthIops) Validate() error { + err := iops.ReadLimit.Validate() if err != nil { return err } - return data.WriteLimit.Validate() + return iops.WriteLimit.Validate() } -type QemuDiskBandwidthDataLimit struct { - Burst QemuDiskBandwidthDataLimitBurst `json:"burst,omitempty"` // 0 = unlimited - Concurrent QemuDiskBandwidthDataLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited +type QemuDiskBandwidthIopsLimit struct { + Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = unlimited + BurstDuration QemuDiskBandwidthBurstDuration `json:"burst_duration,omitempty"` + Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } -func (limit QemuDiskBandwidthDataLimit) Validate() (err error) { +func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { if err = limit.Burst.Validate(); err != nil { return } @@ -529,52 +530,51 @@ func (limit QemuDiskBandwidthDataLimit) Validate() (err error) { return } +type QemuDiskBandwidthIopsLimitBurst uint + const ( - Error_QemuDiskBandwidthDataLimitBurst string = "burst may not be lower then 1 except for 0" + Error_QemuDiskBandwidthIopsLimitBurst string = "burst may not be lower then 10 except for 0" ) -type QemuDiskBandwidthDataLimitBurst float32 - -func (limit QemuDiskBandwidthDataLimitBurst) Validate() error { - if limit != 0 && limit < 1 { - return errors.New(Error_QemuDiskBandwidthDataLimitBurst) +func (limit QemuDiskBandwidthIopsLimitBurst) Validate() error { + if limit != 0 && limit < 10 { + return errors.New(Error_QemuDiskBandwidthIopsLimitBurst) } return nil } +type QemuDiskBandwidthIopsLimitConcurrent uint + const ( - Error_QemuDiskBandwidthDataLimitConcurrent string = "concurrent may not be lower then 1 except for 0" + Error_QemuDiskBandwidthIopsLimitConcurrent string = "concurrent may not be lower then 10 except for 0" ) -type QemuDiskBandwidthDataLimitConcurrent float32 - -func (limit QemuDiskBandwidthDataLimitConcurrent) Validate() error { - if limit != 0 && limit < 1 { - return errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) +func (limit QemuDiskBandwidthIopsLimitConcurrent) Validate() error { + if limit != 0 && limit < 10 { + return errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) } return nil } -type QemuDiskBandwidthIops struct { - ReadLimit QemuDiskBandwidthIopsLimit `json:"read,omitempty"` - WriteLimit QemuDiskBandwidthIopsLimit `json:"write,omitempty"` +type QemuDiskBandwidthMBps struct { + ReadLimit QemuDiskBandwidthMBpsLimit `json:"read,omitempty"` + WriteLimit QemuDiskBandwidthMBpsLimit `json:"write,omitempty"` } -func (iops QemuDiskBandwidthIops) Validate() error { - err := iops.ReadLimit.Validate() +func (data QemuDiskBandwidthMBps) Validate() error { + err := data.ReadLimit.Validate() if err != nil { return err } - return iops.WriteLimit.Validate() + return data.WriteLimit.Validate() } -type QemuDiskBandwidthIopsLimit struct { - Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = unlimited - BurstDuration QemuDiskBandwidthBurstDuration `json:"burst_duration,omitempty"` - Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited +type QemuDiskBandwidthMBpsLimit struct { + Burst QemuDiskBandwidthMBpsLimitBurst `json:"burst,omitempty"` // 0 = unlimited + Concurrent QemuDiskBandwidthMBpsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } -func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { +func (limit QemuDiskBandwidthMBpsLimit) Validate() (err error) { if err = limit.Burst.Validate(); err != nil { return } @@ -582,28 +582,28 @@ func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { return } -type QemuDiskBandwidthIopsLimitBurst uint - const ( - Error_QemuDiskBandwidthIopsLimitBurst string = "burst may not be lower then 10 except for 0" + Error_QemuDiskBandwidthMBpsLimitBurst string = "burst may not be lower then 1 except for 0" ) -func (limit QemuDiskBandwidthIopsLimitBurst) Validate() error { - if limit != 0 && limit < 10 { - return errors.New(Error_QemuDiskBandwidthIopsLimitBurst) +type QemuDiskBandwidthMBpsLimitBurst float32 + +func (limit QemuDiskBandwidthMBpsLimitBurst) Validate() error { + if limit != 0 && limit < 1 { + return errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) } return nil } -type QemuDiskBandwidthIopsLimitConcurrent uint - const ( - Error_QemuDiskBandwidthIopsLimitConcurrent string = "concurrent may not be lower then 10 except for 0" + Error_QemuDiskBandwidthMBpsLimitConcurrent string = "concurrent may not be lower then 1 except for 0" ) -func (limit QemuDiskBandwidthIopsLimitConcurrent) Validate() error { - if limit != 0 && limit < 10 { - return errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent) +type QemuDiskBandwidthMBpsLimitConcurrent float32 + +func (limit QemuDiskBandwidthMBpsLimitConcurrent) Validate() error { + if limit != 0 && limit < 1 { + return errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) } return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 39a54492..943048f5 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -122,17 +122,17 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { }{ // Valid {name: "Valid 00", input: QemuDiskBandwidth{}}, - {name: "Valid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}, - {name: "Valid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}, - {name: "Valid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, - {name: "Valid 04", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, - {name: "Valid 05", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, - {name: "Valid 06", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, - {name: "Valid 07", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}, - {name: "Valid 08", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}}, - {name: "Valid 09", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}}, - {name: "Valid 10", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}}, - {name: "Valid 11", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}}, + {name: "Valid 01", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}, + {name: "Valid 02", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}, + {name: "Valid 03", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0}}}}, + {name: "Valid 04", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 1}}}}, + {name: "Valid 05", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0}}}}, + {name: "Valid 06", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1}}}}, + {name: "Valid 07", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}, + {name: "Valid 08", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0}}}}, + {name: "Valid 09", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 1}}}}, + {name: "Valid 10", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0}}}}, + {name: "Valid 11", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1}}}}, {name: "Valid 12", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}, {name: "Valid 13", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}, {name: "Valid 14", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}}, @@ -145,10 +145,10 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { {name: "Valid 21", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}}, {name: "Valid 22", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, - {name: "Invalid 01", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, - {name: "Invalid 03", input: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, {name: "Invalid 04", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, {name: "Invalid 05", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, {name: "Invalid 06", input: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, @@ -165,29 +165,29 @@ func Test_QemuDiskBandwidth_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthData_Validate(t *testing.T) { +func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthData + input QemuDiskBandwidthIops err error }{ // Valid - {name: "Valid 00", input: QemuDiskBandwidthData{}}, - {name: "Valid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}, - {name: "Valid 02", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, - {name: "Valid 03", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, - {name: "Valid 04", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, - {name: "Valid 05", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, - {name: "Valid 06", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}, - {name: "Valid 07", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0}}}, - {name: "Valid 08", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 1}}}, - {name: "Valid 09", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0}}}, - {name: "Valid 10", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 1}}}, + {name: "Valid 00", input: QemuDiskBandwidthIops{}}, + {name: "Valid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, + {name: "Valid 02", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 03", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 04", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {name: "Valid 05", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + {name: "Valid 06", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, + {name: "Valid 07", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}, + {name: "Valid 08", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, + {name: "Valid 09", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, + {name: "Valid 10", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, - {name: "Invalid 01", input: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, - {name: "Invalid 03", input: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -200,21 +200,21 @@ func Test_QemuDiskBandwidthData_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { +func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthDataLimit + input QemuDiskBandwidthIopsLimit err error }{ // Valid - {name: "Valid 00", input: QemuDiskBandwidthDataLimit{}}, - {name: "Valid 01", input: QemuDiskBandwidthDataLimit{Burst: 0}}, - {name: "Valid 02", input: QemuDiskBandwidthDataLimit{Burst: 1}}, - {name: "Valid 03", input: QemuDiskBandwidthDataLimit{Concurrent: 0}}, - {name: "Valid 04", input: QemuDiskBandwidthDataLimit{Concurrent: 1}}, + {name: "Valid 00", input: QemuDiskBandwidthIopsLimit{}}, + {name: "Valid 01", input: QemuDiskBandwidthIopsLimit{Burst: 0}}, + {name: "Valid 02", input: QemuDiskBandwidthIopsLimit{Burst: 10}}, + {name: "Valid 03", input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, + {name: "Valid 04", input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthDataLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, - {name: "Invalid 01", input: QemuDiskBandwidthDataLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -227,17 +227,17 @@ func Test_QemuDiskBandwidthDataLimit_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthDataLimitBurst_Validate(t *testing.T) { +func Test_QemuDiskBandwidthIopsLimitBurst_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthDataLimitBurst + input QemuDiskBandwidthIopsLimitBurst err error }{ // Valid - {name: "Valid 01", input: 0}, - {name: "Valid 02", input: 1}, + {name: "Valid 03", input: 0}, + {name: "Valid 04", input: 10}, // Invalid - {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthDataLimitBurst)}, + {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -250,17 +250,17 @@ func Test_QemuDiskBandwidthDataLimitBurst_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthDataLimitConcurrent_Validate(t *testing.T) { +func Test_QemuDiskBandwidthIopsLimitConcurrent_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthDataLimitConcurrent + input QemuDiskBandwidthIopsLimitConcurrent err error }{ // Valid - {name: "Valid 01", input: 0}, - {name: "Valid 02", input: 1}, + {name: "Valid 03", input: 0}, + {name: "Valid 04", input: 10}, // Invalid - {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent)}, + {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -273,29 +273,29 @@ func Test_QemuDiskBandwidthDataLimitConcurrent_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { +func Test_QemuDiskBandwidthMBps_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthIops + input QemuDiskBandwidthMBps err error }{ // Valid - {name: "Valid 00", input: QemuDiskBandwidthIops{}}, - {name: "Valid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}, - {name: "Valid 02", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {name: "Valid 03", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {name: "Valid 04", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, - {name: "Valid 05", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, - {name: "Valid 06", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}, - {name: "Valid 07", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 0}}}, - {name: "Valid 08", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 10}}}, - {name: "Valid 09", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 0}}}, - {name: "Valid 10", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 10}}}, + {name: "Valid 00", input: QemuDiskBandwidthMBps{}}, + {name: "Valid 01", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}, + {name: "Valid 02", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0}}}, + {name: "Valid 03", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 1}}}, + {name: "Valid 04", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0}}}, + {name: "Valid 05", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1}}}, + {name: "Valid 06", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}, + {name: "Valid 07", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0}}}, + {name: "Valid 08", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 1}}}, + {name: "Valid 09", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0}}}, + {name: "Valid 10", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1}}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, - {name: "Invalid 01", input: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, - {name: "Invalid 02", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, - {name: "Invalid 03", input: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 9}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, + {name: "Invalid 02", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, + {name: "Invalid 03", input: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -308,21 +308,21 @@ func Test_QemuDiskBandwidthIops_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { +func Test_QemuDiskBandwidthMBpsLimit_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthIopsLimit + input QemuDiskBandwidthMBpsLimit err error }{ // Valid - {name: "Valid 00", input: QemuDiskBandwidthIopsLimit{}}, - {name: "Valid 01", input: QemuDiskBandwidthIopsLimit{Burst: 0}}, - {name: "Valid 02", input: QemuDiskBandwidthIopsLimit{Burst: 10}}, - {name: "Valid 03", input: QemuDiskBandwidthIopsLimit{Concurrent: 0}}, - {name: "Valid 04", input: QemuDiskBandwidthIopsLimit{Concurrent: 10}}, + {name: "Valid 00", input: QemuDiskBandwidthMBpsLimit{}}, + {name: "Valid 01", input: QemuDiskBandwidthMBpsLimit{Burst: 0}}, + {name: "Valid 02", input: QemuDiskBandwidthMBpsLimit{Burst: 1}}, + {name: "Valid 03", input: QemuDiskBandwidthMBpsLimit{Concurrent: 0}}, + {name: "Valid 04", input: QemuDiskBandwidthMBpsLimit{Concurrent: 1}}, // Invalid - {name: "Invalid 00", input: QemuDiskBandwidthIopsLimit{Burst: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, - {name: "Invalid 01", input: QemuDiskBandwidthIopsLimit{Concurrent: 9}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 00", input: QemuDiskBandwidthMBpsLimit{Burst: 0.99}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, + {name: "Invalid 01", input: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -335,17 +335,17 @@ func Test_QemuDiskBandwidthIopsLimit_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthIopsLimitBurst_Validate(t *testing.T) { +func Test_QemuDiskBandwidthMBpsLimitBurst_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthIopsLimitBurst + input QemuDiskBandwidthMBpsLimitBurst err error }{ // Valid - {name: "Valid 03", input: 0}, - {name: "Valid 04", input: 10}, + {name: "Valid 01", input: 0}, + {name: "Valid 02", input: 1}, // Invalid - {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst)}, + {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { @@ -358,17 +358,17 @@ func Test_QemuDiskBandwidthIopsLimitBurst_Validate(t *testing.T) { } } -func Test_QemuDiskBandwidthIopsLimitConcurrent_Validate(t *testing.T) { +func Test_QemuDiskBandwidthMBpsLimitConcurrent_Validate(t *testing.T) { testData := []struct { name string - input QemuDiskBandwidthIopsLimitConcurrent + input QemuDiskBandwidthMBpsLimitConcurrent err error }{ // Valid - {name: "Valid 03", input: 0}, - {name: "Valid 04", input: 10}, + {name: "Valid 01", input: 0}, + {name: "Valid 02", input: 1}, // Invalid - {name: "Invalid 01", input: 9, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent)}, + {name: "Invalid 00", input: 0.99, err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent)}, } for _, test := range testData { t.Run(test.name, func(*testing.T) { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 2755ca46..2e8c24cf 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -11,10 +11,10 @@ import ( func Test_ConfigQemu_mapToApiValues(t *testing.T) { format_Raw := QemuDiskFormat_Raw - float10 := QemuDiskBandwidthDataLimitConcurrent(10.3) - float45 := QemuDiskBandwidthDataLimitConcurrent(45.23) - float79 := QemuDiskBandwidthDataLimitBurst(79.23) - float99 := QemuDiskBandwidthDataLimitBurst(99.2) + float10 := QemuDiskBandwidthMBpsLimitConcurrent(10.3) + float45 := QemuDiskBandwidthMBpsLimitConcurrent(45.23) + float79 := QemuDiskBandwidthMBpsLimitBurst(79.23) + float99 := QemuDiskBandwidthMBpsLimitBurst(99.2) uint23 := QemuDiskBandwidthIopsLimitConcurrent(23) uint34 := QemuDiskBandwidthIopsLimitConcurrent(34) uint78 := QemuDiskBandwidthIopsLimitBurst(78) @@ -57,9 +57,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -89,34 +89,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"ide2": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, @@ -153,6 +125,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Disk.Cache", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Cache: QemuDiskCache_DirectSync}}}}}, output: map[string]interface{}{"ide2": ",backup=0,cache=directsync,replicate=0"}, @@ -191,9 +191,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -221,34 +221,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"ide2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"ide3": ",backup=0,replicate=0"}, @@ -285,6 +257,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"ide1": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide1": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Ide.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"ide2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, {name: "Create Disks.Ide.Disk_X.Passthrough.Cache", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Cache: QemuDiskCache_Unsafe}}}}}, output: map[string]interface{}{"ide2": ",backup=0,cache=unsafe,replicate=0"}, @@ -332,9 +332,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -364,34 +364,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"sata5": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"sata0": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"sata1": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"sata2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"sata3": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, @@ -428,6 +400,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"sata4": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Disk.Cache", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Cache: QemuDiskCache_DirectSync}}}}}, output: map[string]interface{}{"sata5": ",backup=0,cache=directsync,replicate=0"}, @@ -466,9 +466,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -496,34 +496,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"sata3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"sata0": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"sata1": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"sata3": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"sata4": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, @@ -560,6 +532,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"sata5": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"sata1": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"sata2": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"sata3": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Sata.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"sata4": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.Sata.Disk_X.Passthrough.Cache", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, output: map[string]interface{}{"sata0": ",backup=0,cache=unsafe,replicate=0"}, @@ -607,9 +607,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -641,34 +641,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"scsi3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, output: map[string]interface{}{"scsi11": ",backup=0,replicate=0"}, @@ -705,6 +677,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Disk.Cache", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{Cache: QemuDiskCache_DirectSync}}}}}, output: map[string]interface{}{"scsi18": ",backup=0,cache=directsync,replicate=0"}, @@ -751,9 +751,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -783,34 +783,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"scsi3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"scsi11": ",backup=0,replicate=0"}, @@ -847,6 +819,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"scsi17": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"scsi4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"scsi6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_7: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"scsi7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"scsi8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"scsi9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"scsi10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.Scsi.Disk_X.Passthrough.Cache", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, output: map[string]interface{}{"scsi18": ",backup=0,cache=unsafe,replicate=0"}, @@ -902,9 +902,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -935,42 +935,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"virtio3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, - output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, - output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, - output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max=78,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.BurstDuration", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 1}}}}}}}}, - output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max_length=1,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, - output: map[string]interface{}{"virtio7": ",backup=0,iops_rd=34,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, - output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, - output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max=89,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.BurstDuration", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}}}}}}, - output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max_length=2,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, - output: map[string]interface{}{"virtio10": ",backup=0,iops_wr=23,replicate=0"}, - }, {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.iops", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"virtio11": ",backup=0,replicate=0"}, @@ -1007,6 +971,42 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max=78,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.ReadLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 1}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,iops_rd_max_length=1,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint34}}}}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,iops_rd=34,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max=89,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.WriteLimit.BurstDuration", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{BurstDuration: 2}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,iops_wr_max_length=2,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Disk.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, + output: map[string]interface{}{"virtio10": ",backup=0,iops_wr=23,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Disk.Cache", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Cache: QemuDiskCache_DirectSync}}}}}, output: map[string]interface{}{"virtio2": ",backup=0,cache=directsync,replicate=0"}, @@ -1049,9 +1049,9 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99, Concurrent: float10}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79, Concurrent: float45}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99, Concurrent: float10}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79, Concurrent: float45}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: uint78, BurstDuration: 3, Concurrent: uint34}, @@ -1080,34 +1080,6 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{}}}}}}, output: map[string]interface{}{"virtio3": ",backup=0,replicate=0"}, }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{}}}}}}}, - output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: float99}}}}}}}}, - output: map[string]interface{}{"virtio6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.ReadLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: float10}}}}}}}}, - output: map[string]interface{}{"virtio7": ",backup=0,mbps_rd=10.30,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{}}}}}}}}, - output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Burst", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: float79}}}}}}}}, - output: map[string]interface{}{"virtio9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, - }, - {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Data.WriteLimit.Concurrent", - config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: float45}}}}}}}}, - output: map[string]interface{}{"virtio10": ",backup=0,mbps_wr=45.23,replicate=0"}, - }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.Iops", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{}}}}}}}, output: map[string]interface{}{"virtio11": ",backup=0,replicate=0"}, @@ -1144,6 +1116,34 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: uint23}}}}}}}}, output: map[string]interface{}{"virtio1": ",backup=0,iops_wr=23,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{}}}}}}}, + output: map[string]interface{}{"virtio4": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio5": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: float99}}}}}}}}, + output: map[string]interface{}{"virtio6": ",backup=0,mbps_rd_max=99.20,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.ReadLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float10}}}}}}}}, + output: map[string]interface{}{"virtio7": ",backup=0,mbps_rd=10.30,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{}}}}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Burst", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: float79}}}}}}}}, + output: map[string]interface{}{"virtio9": ",backup=0,mbps_wr_max=79.23,replicate=0"}, + }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.Bandwidth.MBps.WriteLimit.Concurrent", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: float45}}}}}}}}, + output: map[string]interface{}{"virtio10": ",backup=0,mbps_wr=45.23,replicate=0"}, + }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.Cache", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Cache: QemuDiskCache_Unsafe}}}}}, output: map[string]interface{}{"virtio2": ",backup=0,cache=unsafe,replicate=0"}, @@ -2312,9 +2312,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57, Concurrent: 1.46}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.57, Concurrent: 1.46}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.55, Concurrent: 2.68}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, @@ -2338,9 +2338,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57, Concurrent: 1.46}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55, Concurrent: 2.68}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.57, Concurrent: 1.46}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.55, Concurrent: 2.68}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, @@ -2472,7 +2472,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,mbps_rd=1.46"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.46}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.46}}}, Format: QemuDiskFormat_Qcow2, Id: uint53, Replicate: true, @@ -2483,7 +2483,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide3": "test2:100/vm-100-disk-53.qcow2,mbps_rd_max=3.57"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.57}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.57}}}, Format: QemuDiskFormat_Qcow2, Id: uint53, Replicate: true, @@ -2494,7 +2494,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,mbps_wr=2.68"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.68}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.68}}}, Format: QemuDiskFormat_Qcow2, Id: uint53, Replicate: true, @@ -2505,7 +2505,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,mbps_wr_max=4.55"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.55}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.55}}}, Format: QemuDiskFormat_Qcow2, Id: uint53, Replicate: true, @@ -2570,9 +2570,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -2681,7 +2681,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -2690,7 +2690,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide3": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -2699,7 +2699,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -2708,7 +2708,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -2790,9 +2790,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -2816,9 +2816,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -2950,7 +2950,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint47, Replicate: true, @@ -2961,7 +2961,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint47, Replicate: true, @@ -2973,8 +2973,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}, }, }, Format: QemuDiskFormat_Qcow2, @@ -2987,7 +2987,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint47, Replicate: true, @@ -3052,9 +3052,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 5, Concurrent: 10}, @@ -3163,7 +3163,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata4": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3172,7 +3172,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3181,7 +3181,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3190,7 +3190,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3272,9 +3272,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -3300,9 +3300,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -3447,7 +3447,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi11": "test:100/vm-100-disk-2.qcow2,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint2, Replicate: true, @@ -3458,7 +3458,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi12": "test:100/vm-100-disk-2.qcow2,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint2, Replicate: true, @@ -3469,7 +3469,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi13": "test:100/vm-100-disk-2.qcow2,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint2, Replicate: true, @@ -3480,7 +3480,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi14": "test:100/vm-100-disk-2.qcow2,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint2, Replicate: true, @@ -3556,9 +3556,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -3678,7 +3678,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi11": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_11: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3687,7 +3687,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi12": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3696,7 +3696,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi13": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3705,7 +3705,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"scsi14": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_14: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -3796,9 +3796,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, @@ -3823,9 +3823,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, @@ -3970,8 +3970,8 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}, }, }, Format: QemuDiskFormat_Qcow2, @@ -3984,7 +3984,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio12": "test2:100/vm-100-disk-31.qcow2,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint31, Replicate: true, @@ -3995,7 +3995,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio13": "test2:100/vm-100-disk-31.qcow2,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint31, Replicate: true, @@ -4006,7 +4006,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio14": "test2:100/vm-100-disk-31.qcow2,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, Format: QemuDiskFormat_Qcow2, Id: uint31, Replicate: true, @@ -4071,9 +4071,9 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { AsyncIO: QemuDiskAsyncIO_Native, Backup: false, Bandwidth: QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51, Concurrent: 2.51}, + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, }, Iops: QemuDiskBandwidthIops{ ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, @@ -4192,7 +4192,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio11": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd=1.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_11: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 1.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 1.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -4201,7 +4201,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio12": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_rd_max=3.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 3.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -4210,7 +4210,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio13": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr=2.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 2.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 2.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -4219,7 +4219,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { input: map[string]interface{}{"virtio14": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,mbps_wr_max=4.51"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_14: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ Backup: true, - Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 4.51}}}, + Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51}}}, File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", Replicate: true, }}}}}, @@ -4291,12 +4291,12 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { } func Test_ConfigQemu_Validate(t *testing.T) { BandwidthValid0 := QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{ Burst: 0, Concurrent: 0, }, - WriteLimit: QemuDiskBandwidthDataLimit{ + WriteLimit: QemuDiskBandwidthMBpsLimit{ Burst: 0, Concurrent: 0, }, @@ -4313,12 +4313,12 @@ func Test_ConfigQemu_Validate(t *testing.T) { }, } BandwidthValid1 := QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{ Burst: 1, Concurrent: 1, }, - WriteLimit: QemuDiskBandwidthDataLimit{ + WriteLimit: QemuDiskBandwidthMBpsLimit{ Burst: 1, Concurrent: 1, }, @@ -4335,12 +4335,12 @@ func Test_ConfigQemu_Validate(t *testing.T) { }, } BandwidthValid2 := QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{ Burst: 1, Concurrent: 0, }, - WriteLimit: QemuDiskBandwidthDataLimit{ + WriteLimit: QemuDiskBandwidthMBpsLimit{ Burst: 1, Concurrent: 0, }, @@ -4357,12 +4357,12 @@ func Test_ConfigQemu_Validate(t *testing.T) { }, } BandwidthValid3 := QemuDiskBandwidth{ - Data: QemuDiskBandwidthData{ - ReadLimit: QemuDiskBandwidthDataLimit{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{ Burst: 0, Concurrent: 1, }, - WriteLimit: QemuDiskBandwidthDataLimit{ + WriteLimit: QemuDiskBandwidthMBpsLimit{ Burst: 0, Concurrent: 1, }, @@ -4997,21 +4997,21 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), }, - {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), + {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), }, {name: `Invalid Disks Disk Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, @@ -5075,22 +5075,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5107,6 +5091,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Disk Sata QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5153,22 +5153,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_6: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5185,6 +5169,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Disk: &QemuScsiDisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Disk Scsi QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_10: &QemuScsiStorage{Disk: &QemuScsiDisk{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5231,22 +5231,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_6: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5263,6 +5247,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Disk VirtIO QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5305,22 +5305,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5337,6 +5321,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Passthrough Ide QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5358,22 +5358,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5390,6 +5374,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_2: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Passthrough Sata QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5411,22 +5411,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_5: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5443,6 +5427,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_8: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_2: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_3: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_4: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Passthrough Scsi QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_9: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), @@ -5464,22 +5464,6 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: "invalid"}}}}}, err: QemuDiskAsyncIO("").Error(), }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 0`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 0`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{ReadLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitBurst) 1`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Burst: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitBurst), - }, - {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthDataLimitConcurrent) 1`, - input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Data: QemuDiskBandwidthData{WriteLimit: QemuDiskBandwidthDataLimit{Concurrent: 0.99}}}}}}}}, - err: errors.New(Error_QemuDiskBandwidthDataLimitConcurrent), - }, {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthIopsLimitBurst) 0`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 9}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitBurst), @@ -5496,6 +5480,22 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{Iops: QemuDiskBandwidthIops{WriteLimit: QemuDiskBandwidthIopsLimit{Concurrent: 6}}}}}}}}, err: errors.New(Error_QemuDiskBandwidthIopsLimitConcurrent), }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 0`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{ReadLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitBurst) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitBurst), + }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent) 1`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_4: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Bandwidth: QemuDiskBandwidth{MBps: QemuDiskBandwidthMBps{WriteLimit: QemuDiskBandwidthMBpsLimit{Concurrent: 0.99}}}}}}}}, + err: errors.New(Error_QemuDiskBandwidthMBpsLimitConcurrent), + }, {name: `Invalid Disks Passthrough VirtIO QemuDiskCache("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Cache: "invalid"}}}}}, err: QemuDiskCache("").Error(), From e2755e4df335fec2642ea53d6f1d54d11f98f5b8 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 3 Apr 2023 11:18:12 +0000 Subject: [PATCH 128/191] fix: merge conflicts Reimplement af4dd9aa7b0409bb150e2f5d3d13ba45933a4e66 and 37bbfd5bb759e04864c8bd575365878826af9dc3 --- proxmox/config_qemu.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 9b8d95be..4568ab39 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -290,6 +290,9 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (rebootRequire if config.QemuVcpus >= 1 { params["vcpus"] = config.QemuVcpus } + if config.Smbios1 != "" { + params["smbios1"] = config.Smbios1 + } if config.Iso != nil { if config.Disks == nil { @@ -463,6 +466,9 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error if _, isSet := params["tags"]; isSet { config.Tags = strings.TrimSpace(params["tags"].(string)) } + if _, isSet := params["smbios1"]; isSet { + config.Smbios1 = params["smbios1"].(string) + } ipconfigNames := []string{} From 29ce746d02b89607647d0d424d8518aa10828211 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 4 Apr 2023 20:12:26 +0000 Subject: [PATCH 129/191] refactor: make `LinkedVmId` part of `ConfigQemu` before it was defined of each disk, but it is the same for all linked disk. thats why it's moved to `ConfigQemu`. when the vm has no linked disks `LinkedVmId` becomes `0` --- proxmox/config_qemu.go | 13 +- proxmox/config_qemu_disk.go | 82 +++-- proxmox/config_qemu_disk_ide.go | 100 +++--- proxmox/config_qemu_disk_sata.go | 104 +++--- proxmox/config_qemu_disk_scsi.go | 166 ++++----- proxmox/config_qemu_disk_test.go | 26 ++ proxmox/config_qemu_disk_virtio.go | 130 +++---- proxmox/config_qemu_test.go | 528 ++++++++++++++++------------- 8 files changed, 613 insertions(+), 536 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 4568ab39..14340834 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -55,6 +55,7 @@ type ConfigQemu struct { Hotplug string `json:"hotplug,omitempty"` // TODO should be a struct Ipconfig IpconfigMap `json:"ipconfig,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) Iso *IsoFile `json:"iso,omitempty"` // Same as Disks.Ide.Disk_2.CdRom.Iso + LinkedVmId uint `json:"linked_id,omitempty"` // Only returned setting it has no effect Machine string `json:"machine,omitempty"` // TODO should be custom type with enum Memory int `json:"memory,omitempty"` // TODO should be uint Name string `json:"name,omitempty"` // TODO should be custom type as there are character and length limitations @@ -311,14 +312,16 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (rebootRequire // Disks if currentConfig.Disks != nil { if config.Disks != nil { - delete := config.Disks.mapToApiValues(*currentConfig.Disks, uint(config.VmID), params) + // Create,Update,Delete + delete := config.Disks.mapToApiValues(*currentConfig.Disks, uint(config.VmID), currentConfig.LinkedVmId, params) if delete != "" { itemsToDelete = AddToList(itemsToDelete, delete) } } } else { if config.Disks != nil { - config.Disks.mapToApiValues(QemuStorages{}, uint(config.VmID), params) + // Create + config.Disks.mapToApiValues(QemuStorages{}, uint(config.VmID), 0, params) } } @@ -488,7 +491,11 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } - config.Disks = QemuStorages{}.mapToStruct(params) + linkedVmId := uint(0) + config.Disks = QemuStorages{}.mapToStruct(params, &linkedVmId) + if linkedVmId != 0 { + config.LinkedVmId = linkedVmId + } if config.Disks != nil && config.Disks.Ide != nil && config.Disks.Ide.Disk_2 != nil && config.Disks.Ide.Disk_2.CdRom != nil { config.Iso = config.Disks.Ide.Disk_2.CdRom.Iso diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index faef43e5..ce2fd9c6 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -184,15 +184,15 @@ type qemuDisk struct { Disk bool // true = disk, false = passthrough EmulateSSD bool // Only set for ide,sata,scsi // TODO custom type - File string // Only set for Passthrough. - Format QemuDiskFormat // Only set for Disk - Id uint // Only set for Disk - IOThread bool // Only set for scsi,virtio - LinkedClone *QemuDiskLinkedClone // Only set for Disk - ReadOnly bool // Only set for scsi,virtio - Replicate bool - Serial QemuDiskSerial - Size uint + File string // Only set for Passthrough. + Format QemuDiskFormat // Only set for Disk + Id uint // Only set for Disk + IOThread bool // Only set for scsi,virtio + LinkedDiskId *uint // Only set for Disk + ReadOnly bool // Only set for scsi,virtio + Replicate bool + Serial QemuDiskSerial + Size uint // TODO custom type Storage string // Only set for Disk Type qemuDiskType @@ -206,7 +206,7 @@ const ( ) // Maps all the disk related settings to api values proxmox understands. -func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFormat QemuDiskFormat, create bool) (settings string) { +func (disk qemuDisk) mapToApiValues(vmID, LinkedVmId uint, currentStorage string, currentFormat QemuDiskFormat, create bool) (settings string) { if disk.Storage != "" { if create { settings = disk.Storage + ":" + strconv.Itoa(int(disk.Size)) @@ -214,10 +214,10 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor tmpId := strconv.Itoa(int(vmID)) settings = tmpId + "/vm-" + tmpId + "-disk-" + strconv.Itoa(int(disk.Id)) + "." + string(disk.Format) // storage:100/vm-100-disk-0.raw - if disk.LinkedClone != nil && disk.Storage == currentStorage && disk.Format == currentFormat { + if disk.LinkedDiskId != nil && disk.Storage == currentStorage && disk.Format == currentFormat { // storage:110/base-110-disk-1.raw/100/vm-100-disk-0.raw - tmpId = strconv.Itoa(int(disk.LinkedClone.VmId)) - settings = tmpId + "/base-" + tmpId + "-disk-" + strconv.Itoa(int(disk.LinkedClone.DiskId)) + "." + string(disk.Format) + "/" + settings + tmpId = strconv.Itoa(int(LinkedVmId)) + settings = tmpId + "/base-" + tmpId + "-disk-" + strconv.Itoa(int(*disk.LinkedDiskId)) + "." + string(disk.Format) + "/" + settings } settings = disk.Storage + ":" + settings } @@ -300,7 +300,7 @@ func (disk qemuDisk) mapToApiValues(vmID uint, currentStorage string, currentFor } // Maps all the disk related settings to our own data structure. -func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { +func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { if len(settings) == 0 { return nil } @@ -309,8 +309,8 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if settings[0][0][0:1] == "/" { disk.File = settings[0][0] } else { - // storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2, - // storage:100/vm-100-disk-0.qcow2, + // storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2 + // storage:100/vm-100-disk-0.qcow2 diskAndPath := strings.Split(settings[0][0], ":") disk.Storage = diskAndPath[0] if len(diskAndPath) == 2 { @@ -318,13 +318,12 @@ func (qemuDisk) mapToStruct(settings [][]string) *qemuDisk { if len(pathParts) == 4 { var tmpDiskId int tmpVmId, _ := strconv.Atoi(pathParts[0]) + *linkedVmId = uint(tmpVmId) tmp := strings.Split(strings.Split(pathParts[1], ".")[0], "-") if len(tmp) > 1 { tmpDiskId, _ = strconv.Atoi(tmp[len(tmp)-1]) - } - disk.LinkedClone = &QemuDiskLinkedClone{ - VmId: uint(tmpVmId), - DiskId: uint(tmpDiskId), + tmpDiskIdPointer := uint(tmpDiskId) + disk.LinkedDiskId = &tmpDiskIdPointer } } if len(pathParts) > 1 { @@ -715,11 +714,6 @@ func (id QemuDiskId) Validate() error { return errors.New(ERROR_QemuDiskId_Invalid) } -type QemuDiskLinkedClone struct { - DiskId uint `json:"disk"` - VmId uint `json:"vm"` -} - type qemuDiskMark struct { Format QemuDiskFormat Id QemuDiskId @@ -836,7 +830,7 @@ type qemuStorage struct { Passthrough *qemuDisk } -func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uint, id QemuDiskId, params map[string]interface{}, delete string) string { +func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID, linkedVmId uint, id QemuDiskId, params map[string]interface{}, delete string) string { if storage == nil { return delete } @@ -878,20 +872,20 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin if storage.Disk != nil { if currentStorage == nil || currentStorage.Disk == nil { // Create - params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, 0, "", "", true) } else { if storage.Disk.Size >= currentStorage.Disk.Size { // Update storage.Disk.Id = currentStorage.Disk.Id - storage.Disk.LinkedClone = currentStorage.Disk.LinkedClone - disk := storage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) - if disk != currentStorage.Disk.mapToApiValues(vmID, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) { + storage.Disk.LinkedDiskId = currentStorage.Disk.LinkedDiskId + disk := storage.Disk.mapToApiValues(vmID, linkedVmId, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) + if disk != currentStorage.Disk.mapToApiValues(vmID, linkedVmId, currentStorage.Disk.Storage, currentStorage.Disk.Format, false) { params[string(id)] = disk } } else { // Delete and Create // creating a disk on top of an existing disk is the same as detaching the disk and creating a new one. - params[string(id)] = storage.Disk.mapToApiValues(vmID, "", "", true) + params[string(id)] = storage.Disk.mapToApiValues(vmID, 0, "", "", true) } } return delete @@ -903,11 +897,11 @@ func (storage *qemuStorage) mapToApiValues(currentStorage *qemuStorage, vmID uin if storage.Passthrough != nil { if currentStorage == nil || currentStorage.Passthrough == nil { // Create - params[string(id)] = storage.Passthrough.mapToApiValues(0, "", "", false) + params[string(id)] = storage.Passthrough.mapToApiValues(0, 0, "", "", false) } else { // Update - passthrough := storage.Passthrough.mapToApiValues(0, "", "", false) - if passthrough != currentStorage.Passthrough.mapToApiValues(0, "", "", false) { + passthrough := storage.Passthrough.mapToApiValues(0, 0, "", "", false) + if passthrough != currentStorage.Passthrough.mapToApiValues(0, 0, "", "", false) { params[string(id)] = passthrough } } @@ -930,28 +924,28 @@ type QemuStorages struct { VirtIO *QemuVirtIODisks `json:"virtio,omitempty"` } -func (storages QemuStorages) mapToApiValues(currentStorages QemuStorages, vmID uint, params map[string]interface{}) (delete string) { +func (storages QemuStorages) mapToApiValues(currentStorages QemuStorages, vmID, linkedVmId uint, params map[string]interface{}) (delete string) { if storages.Ide != nil { - delete = storages.Ide.mapToApiValues(currentStorages.Ide, vmID, params, delete) + delete = storages.Ide.mapToApiValues(currentStorages.Ide, vmID, linkedVmId, params, delete) } if storages.Sata != nil { - delete = storages.Sata.mapToApiValues(currentStorages.Sata, vmID, params, delete) + delete = storages.Sata.mapToApiValues(currentStorages.Sata, vmID, linkedVmId, params, delete) } if storages.Scsi != nil { - delete = storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, params, delete) + delete = storages.Scsi.mapToApiValues(currentStorages.Scsi, vmID, linkedVmId, params, delete) } if storages.VirtIO != nil { - delete = storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, params, delete) + delete = storages.VirtIO.mapToApiValues(currentStorages.VirtIO, vmID, linkedVmId, params, delete) } return delete } -func (QemuStorages) mapToStruct(params map[string]interface{}) *QemuStorages { +func (QemuStorages) mapToStruct(params map[string]interface{}, linkedVmId *uint) *QemuStorages { storage := QemuStorages{ - Ide: QemuIdeDisks{}.mapToStruct(params), - Sata: QemuSataDisks{}.mapToStruct(params), - Scsi: QemuScsiDisks{}.mapToStruct(params), - VirtIO: QemuVirtIODisks{}.mapToStruct(params), + Ide: QemuIdeDisks{}.mapToStruct(params, linkedVmId), + Sata: QemuSataDisks{}.mapToStruct(params, linkedVmId), + Scsi: QemuScsiDisks{}.mapToStruct(params, linkedVmId), + VirtIO: QemuVirtIODisks{}.mapToStruct(params, linkedVmId), } if storage.Ide != nil || storage.Sata != nil || storage.Scsi != nil || storage.VirtIO != nil { return &storage diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index b7dd1eb8..d0746259 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -3,38 +3,38 @@ package proxmox import "strconv" type QemuIdeDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedClone is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - LinkedClone: disk.LinkedClone, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: ide, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedDiskId: disk.LinkedDiskId, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: ide, } } @@ -49,7 +49,7 @@ type QemuIdeDisks struct { Disk_3 *QemuIdeStorage `json:"3,omitempty"` } -func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, params map[string]interface{}, delete string) string { +func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID, LinkedVmId uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuIdeDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -57,7 +57,7 @@ func (disks QemuIdeDisks) mapToApiValues(currentDisks *QemuIdeDisks, vmID uint, diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("ide"+strconv.Itoa(int(i))), params, delete) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, LinkedVmId, QemuDiskId("ide"+strconv.Itoa(int(i))), params, delete) } return delete } @@ -71,23 +71,23 @@ func (disks QemuIdeDisks) mapToIntMap() map[uint8]*QemuIdeStorage { } } -func (QemuIdeDisks) mapToStruct(params map[string]interface{}) *QemuIdeDisks { +func (QemuIdeDisks) mapToStruct(params map[string]interface{}, linkedVmId *uint) *QemuIdeDisks { disks := QemuIdeDisks{} var structPopulated bool if _, isSet := params["ide0"]; isSet { - disks.Disk_0 = QemuIdeStorage{}.mapToStruct(params["ide0"].(string)) + disks.Disk_0 = QemuIdeStorage{}.mapToStruct(params["ide0"].(string), linkedVmId) structPopulated = true } if _, isSet := params["ide1"]; isSet { - disks.Disk_1 = QemuIdeStorage{}.mapToStruct(params["ide1"].(string)) + disks.Disk_1 = QemuIdeStorage{}.mapToStruct(params["ide1"].(string), linkedVmId) structPopulated = true } if _, isSet := params["ide2"]; isSet { - disks.Disk_2 = QemuIdeStorage{}.mapToStruct(params["ide2"].(string)) + disks.Disk_2 = QemuIdeStorage{}.mapToStruct(params["ide2"].(string), linkedVmId) structPopulated = true } if _, isSet := params["ide3"]; isSet { - disks.Disk_3 = QemuIdeStorage{}.mapToStruct(params["ide3"].(string)) + disks.Disk_3 = QemuIdeStorage{}.mapToStruct(params["ide3"].(string), linkedVmId) structPopulated = true } if structPopulated { @@ -204,7 +204,7 @@ func (storage *QemuIdeStorage) convertDataStructureMark() *qemuDiskMark { return nil } -func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { +func (QemuIdeStorage) mapToStruct(param string, LinkedVmId *uint) *QemuIdeStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { @@ -215,25 +215,25 @@ func (QemuIdeStorage) mapToStruct(param string) *QemuIdeStorage { } } - tmpDisk := qemuDisk{}.mapToStruct(settings) + tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) if tmpDisk == nil { return nil } if tmpDisk.File == "" { return &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - LinkedClone: tmpDisk.LinkedClone, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedDiskId: tmpDisk.LinkedDiskId, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index f0f214e0..3e1cb7db 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -3,38 +3,38 @@ package proxmox import "strconv" type QemuSataDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedClone is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - LinkedClone: disk.LinkedClone, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: sata, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedDiskId: disk.LinkedDiskId, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: sata, } } @@ -51,7 +51,7 @@ type QemuSataDisks struct { Disk_5 *QemuSataStorage `json:"5,omitempty"` } -func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint, params map[string]interface{}, delete string) string { +func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID, LinkedVmId uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuSataDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -59,7 +59,7 @@ func (disks QemuSataDisks) mapToApiValues(currentDisks *QemuSataDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("sata"+strconv.Itoa(int(i))), params, delete) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, LinkedVmId, QemuDiskId("sata"+strconv.Itoa(int(i))), params, delete) } return delete } @@ -75,31 +75,31 @@ func (disks QemuSataDisks) mapToIntMap() map[uint8]*QemuSataStorage { } } -func (QemuSataDisks) mapToStruct(params map[string]interface{}) *QemuSataDisks { +func (QemuSataDisks) mapToStruct(params map[string]interface{}, linkedVmId *uint) *QemuSataDisks { disks := QemuSataDisks{} var structPopulated bool if _, isSet := params["sata0"]; isSet { - disks.Disk_0 = QemuSataStorage{}.mapToStruct(params["sata0"].(string)) + disks.Disk_0 = QemuSataStorage{}.mapToStruct(params["sata0"].(string), linkedVmId) structPopulated = true } if _, isSet := params["sata1"]; isSet { - disks.Disk_1 = QemuSataStorage{}.mapToStruct(params["sata1"].(string)) + disks.Disk_1 = QemuSataStorage{}.mapToStruct(params["sata1"].(string), linkedVmId) structPopulated = true } if _, isSet := params["sata2"]; isSet { - disks.Disk_2 = QemuSataStorage{}.mapToStruct(params["sata2"].(string)) + disks.Disk_2 = QemuSataStorage{}.mapToStruct(params["sata2"].(string), linkedVmId) structPopulated = true } if _, isSet := params["sata3"]; isSet { - disks.Disk_3 = QemuSataStorage{}.mapToStruct(params["sata3"].(string)) + disks.Disk_3 = QemuSataStorage{}.mapToStruct(params["sata3"].(string), linkedVmId) structPopulated = true } if _, isSet := params["sata4"]; isSet { - disks.Disk_4 = QemuSataStorage{}.mapToStruct(params["sata4"].(string)) + disks.Disk_4 = QemuSataStorage{}.mapToStruct(params["sata4"].(string), linkedVmId) structPopulated = true } if _, isSet := params["sata5"]; isSet { - disks.Disk_5 = QemuSataStorage{}.mapToStruct(params["sata5"].(string)) + disks.Disk_5 = QemuSataStorage{}.mapToStruct(params["sata5"].(string), linkedVmId) structPopulated = true } if structPopulated { @@ -216,7 +216,7 @@ func (storage *QemuSataStorage) convertDataStructureMark() *qemuDiskMark { return nil } -func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { +func (QemuSataStorage) mapToStruct(param string, LinkedVmId *uint) *QemuSataStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { @@ -227,25 +227,25 @@ func (QemuSataStorage) mapToStruct(param string) *QemuSataStorage { } } - tmpDisk := qemuDisk{}.mapToStruct(settings) + tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) if tmpDisk == nil { return nil } if tmpDisk.File == "" { return &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - LinkedClone: tmpDisk.LinkedClone, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedDiskId: tmpDisk.LinkedDiskId, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuSataStorage{Passthrough: &QemuSataPassthrough{ diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 2cc6cb6d..43b83be8 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -3,42 +3,42 @@ package proxmox import "strconv" type QemuScsiDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedCloneId is only returned and setting it has no effect - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - LinkedClone: disk.LinkedClone, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: scsi, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedDiskId: disk.LinkedDiskId, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: scsi, } } @@ -80,7 +80,7 @@ type QemuScsiDisks struct { Disk_30 *QemuScsiStorage `json:"30,omitempty"` } -func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint, params map[string]interface{}, delete string) string { +func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID, linkedVmId uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuScsiDisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -88,7 +88,7 @@ func (disks QemuScsiDisks) mapToApiValues(currentDisks *QemuScsiDisks, vmID uint diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("scsi"+strconv.Itoa(int(i))), params, delete) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, linkedVmId, QemuDiskId("scsi"+strconv.Itoa(int(i))), params, delete) } return delete } @@ -129,131 +129,131 @@ func (disks QemuScsiDisks) mapToIntMap() map[uint8]*QemuScsiStorage { } } -func (QemuScsiDisks) mapToStruct(params map[string]interface{}) *QemuScsiDisks { +func (QemuScsiDisks) mapToStruct(params map[string]interface{}, linkedVmId *uint) *QemuScsiDisks { disks := QemuScsiDisks{} var structPopulated bool if _, isSet := params["scsi0"]; isSet { - disks.Disk_0 = QemuScsiStorage{}.mapToStruct(params["scsi0"].(string)) + disks.Disk_0 = QemuScsiStorage{}.mapToStruct(params["scsi0"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi1"]; isSet { - disks.Disk_1 = QemuScsiStorage{}.mapToStruct(params["scsi1"].(string)) + disks.Disk_1 = QemuScsiStorage{}.mapToStruct(params["scsi1"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi2"]; isSet { - disks.Disk_2 = QemuScsiStorage{}.mapToStruct(params["scsi2"].(string)) + disks.Disk_2 = QemuScsiStorage{}.mapToStruct(params["scsi2"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi3"]; isSet { - disks.Disk_3 = QemuScsiStorage{}.mapToStruct(params["scsi3"].(string)) + disks.Disk_3 = QemuScsiStorage{}.mapToStruct(params["scsi3"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi4"]; isSet { - disks.Disk_4 = QemuScsiStorage{}.mapToStruct(params["scsi4"].(string)) + disks.Disk_4 = QemuScsiStorage{}.mapToStruct(params["scsi4"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi5"]; isSet { - disks.Disk_5 = QemuScsiStorage{}.mapToStruct(params["scsi5"].(string)) + disks.Disk_5 = QemuScsiStorage{}.mapToStruct(params["scsi5"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi6"]; isSet { - disks.Disk_6 = QemuScsiStorage{}.mapToStruct(params["scsi6"].(string)) + disks.Disk_6 = QemuScsiStorage{}.mapToStruct(params["scsi6"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi7"]; isSet { - disks.Disk_7 = QemuScsiStorage{}.mapToStruct(params["scsi7"].(string)) + disks.Disk_7 = QemuScsiStorage{}.mapToStruct(params["scsi7"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi8"]; isSet { - disks.Disk_8 = QemuScsiStorage{}.mapToStruct(params["scsi8"].(string)) + disks.Disk_8 = QemuScsiStorage{}.mapToStruct(params["scsi8"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi9"]; isSet { - disks.Disk_9 = QemuScsiStorage{}.mapToStruct(params["scsi9"].(string)) + disks.Disk_9 = QemuScsiStorage{}.mapToStruct(params["scsi9"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi10"]; isSet { - disks.Disk_10 = QemuScsiStorage{}.mapToStruct(params["scsi10"].(string)) + disks.Disk_10 = QemuScsiStorage{}.mapToStruct(params["scsi10"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi11"]; isSet { - disks.Disk_11 = QemuScsiStorage{}.mapToStruct(params["scsi11"].(string)) + disks.Disk_11 = QemuScsiStorage{}.mapToStruct(params["scsi11"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi12"]; isSet { - disks.Disk_12 = QemuScsiStorage{}.mapToStruct(params["scsi12"].(string)) + disks.Disk_12 = QemuScsiStorage{}.mapToStruct(params["scsi12"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi13"]; isSet { - disks.Disk_13 = QemuScsiStorage{}.mapToStruct(params["scsi13"].(string)) + disks.Disk_13 = QemuScsiStorage{}.mapToStruct(params["scsi13"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi14"]; isSet { - disks.Disk_14 = QemuScsiStorage{}.mapToStruct(params["scsi14"].(string)) + disks.Disk_14 = QemuScsiStorage{}.mapToStruct(params["scsi14"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi15"]; isSet { - disks.Disk_15 = QemuScsiStorage{}.mapToStruct(params["scsi15"].(string)) + disks.Disk_15 = QemuScsiStorage{}.mapToStruct(params["scsi15"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi16"]; isSet { - disks.Disk_16 = QemuScsiStorage{}.mapToStruct(params["scsi16"].(string)) + disks.Disk_16 = QemuScsiStorage{}.mapToStruct(params["scsi16"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi17"]; isSet { - disks.Disk_17 = QemuScsiStorage{}.mapToStruct(params["scsi17"].(string)) + disks.Disk_17 = QemuScsiStorage{}.mapToStruct(params["scsi17"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi18"]; isSet { - disks.Disk_18 = QemuScsiStorage{}.mapToStruct(params["scsi18"].(string)) + disks.Disk_18 = QemuScsiStorage{}.mapToStruct(params["scsi18"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi19"]; isSet { - disks.Disk_19 = QemuScsiStorage{}.mapToStruct(params["scsi19"].(string)) + disks.Disk_19 = QemuScsiStorage{}.mapToStruct(params["scsi19"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi20"]; isSet { - disks.Disk_20 = QemuScsiStorage{}.mapToStruct(params["scsi20"].(string)) + disks.Disk_20 = QemuScsiStorage{}.mapToStruct(params["scsi20"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi21"]; isSet { - disks.Disk_21 = QemuScsiStorage{}.mapToStruct(params["scsi21"].(string)) + disks.Disk_21 = QemuScsiStorage{}.mapToStruct(params["scsi21"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi22"]; isSet { - disks.Disk_22 = QemuScsiStorage{}.mapToStruct(params["scsi22"].(string)) + disks.Disk_22 = QemuScsiStorage{}.mapToStruct(params["scsi22"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi23"]; isSet { - disks.Disk_23 = QemuScsiStorage{}.mapToStruct(params["scsi23"].(string)) + disks.Disk_23 = QemuScsiStorage{}.mapToStruct(params["scsi23"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi24"]; isSet { - disks.Disk_24 = QemuScsiStorage{}.mapToStruct(params["scsi24"].(string)) + disks.Disk_24 = QemuScsiStorage{}.mapToStruct(params["scsi24"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi25"]; isSet { - disks.Disk_25 = QemuScsiStorage{}.mapToStruct(params["scsi25"].(string)) + disks.Disk_25 = QemuScsiStorage{}.mapToStruct(params["scsi25"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi26"]; isSet { - disks.Disk_26 = QemuScsiStorage{}.mapToStruct(params["scsi26"].(string)) + disks.Disk_26 = QemuScsiStorage{}.mapToStruct(params["scsi26"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi27"]; isSet { - disks.Disk_27 = QemuScsiStorage{}.mapToStruct(params["scsi27"].(string)) + disks.Disk_27 = QemuScsiStorage{}.mapToStruct(params["scsi27"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi28"]; isSet { - disks.Disk_28 = QemuScsiStorage{}.mapToStruct(params["scsi28"].(string)) + disks.Disk_28 = QemuScsiStorage{}.mapToStruct(params["scsi28"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi29"]; isSet { - disks.Disk_29 = QemuScsiStorage{}.mapToStruct(params["scsi29"].(string)) + disks.Disk_29 = QemuScsiStorage{}.mapToStruct(params["scsi29"].(string), linkedVmId) structPopulated = true } if _, isSet := params["scsi30"]; isSet { - disks.Disk_30 = QemuScsiStorage{}.mapToStruct(params["scsi30"].(string)) + disks.Disk_30 = QemuScsiStorage{}.mapToStruct(params["scsi30"].(string), linkedVmId) structPopulated = true } if structPopulated { @@ -374,7 +374,7 @@ func (storage *QemuScsiStorage) convertDataStructureMark() *qemuDiskMark { return nil } -func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { +func (QemuScsiStorage) mapToStruct(param string, LinkedVmId *uint) *QemuScsiStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { @@ -385,27 +385,27 @@ func (QemuScsiStorage) mapToStruct(param string) *QemuScsiStorage { } } - tmpDisk := qemuDisk{}.mapToStruct(settings) + tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) if tmpDisk == nil { return nil } if tmpDisk.File == "" { return &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - LinkedClone: tmpDisk.LinkedClone, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedDiskId: tmpDisk.LinkedDiskId, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 943048f5..167b8f07 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -87,6 +87,32 @@ func Test_QemuCloudInitDisk_Validate(t *testing.T) { } } +func Test_qemuDisk_mapToStruct(t *testing.T) { + tests := []struct { + name string + input [][]string + linkedVmId uint + output uint + }{ + {name: "Don't Update LinkedVmId", + input: [][]string{{"storage:100/vm-100-disk-0.qcow2"}}, + linkedVmId: 110, + output: 110, + }, + {name: "Update LinkedVmId", + input: [][]string{{"storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2"}}, + output: 110, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + linkedVmId := uint(test.linkedVmId) + qemuDisk{}.mapToStruct(test.input, &linkedVmId) + require.Equal(t, test.output, linkedVmId, test.name) + }) + } +} + func Test_QemuDiskAsyncIO_Validate(t *testing.T) { testData := []struct { name string diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 4fd8c273..95485877 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -3,40 +3,40 @@ package proxmox import "strconv" type QemuVirtIODisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - LinkedClone *QemuDiskLinkedClone `json:"linked"` //LinkedCloneId is only returned and setting it has no effect - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` } func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - LinkedClone: disk.LinkedClone, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: virtIO, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedDiskId: disk.LinkedDiskId, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: virtIO, } } @@ -63,7 +63,7 @@ type QemuVirtIODisks struct { Disk_15 *QemuVirtIOStorage `json:"15,omitempty"` } -func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID uint, params map[string]interface{}, delete string) string { +func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID, linkedVmId uint, params map[string]interface{}, delete string) string { tmpCurrentDisks := QemuVirtIODisks{} if currentDisks != nil { tmpCurrentDisks = *currentDisks @@ -71,7 +71,7 @@ func (disks QemuVirtIODisks) mapToApiValues(currentDisks *QemuVirtIODisks, vmID diskMap := disks.mapToIntMap() currentDiskMap := tmpCurrentDisks.mapToIntMap() for i := range diskMap { - delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, QemuDiskId("virtio"+strconv.Itoa(int(i))), params, delete) + delete = diskMap[i].convertDataStructure().mapToApiValues(currentDiskMap[i].convertDataStructure(), vmID, linkedVmId, QemuDiskId("virtio"+strconv.Itoa(int(i))), params, delete) } return delete } @@ -97,71 +97,71 @@ func (disks QemuVirtIODisks) mapToIntMap() map[uint8]*QemuVirtIOStorage { } } -func (QemuVirtIODisks) mapToStruct(params map[string]interface{}) *QemuVirtIODisks { +func (QemuVirtIODisks) mapToStruct(params map[string]interface{}, linkedVmId *uint) *QemuVirtIODisks { disks := QemuVirtIODisks{} var structPopulated bool if _, isSet := params["virtio0"]; isSet { - disks.Disk_0 = QemuVirtIOStorage{}.mapToStruct(params["virtio0"].(string)) + disks.Disk_0 = QemuVirtIOStorage{}.mapToStruct(params["virtio0"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio1"]; isSet { - disks.Disk_1 = QemuVirtIOStorage{}.mapToStruct(params["virtio1"].(string)) + disks.Disk_1 = QemuVirtIOStorage{}.mapToStruct(params["virtio1"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio2"]; isSet { - disks.Disk_2 = QemuVirtIOStorage{}.mapToStruct(params["virtio2"].(string)) + disks.Disk_2 = QemuVirtIOStorage{}.mapToStruct(params["virtio2"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio3"]; isSet { - disks.Disk_3 = QemuVirtIOStorage{}.mapToStruct(params["virtio3"].(string)) + disks.Disk_3 = QemuVirtIOStorage{}.mapToStruct(params["virtio3"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio4"]; isSet { - disks.Disk_4 = QemuVirtIOStorage{}.mapToStruct(params["virtio4"].(string)) + disks.Disk_4 = QemuVirtIOStorage{}.mapToStruct(params["virtio4"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio5"]; isSet { - disks.Disk_5 = QemuVirtIOStorage{}.mapToStruct(params["virtio5"].(string)) + disks.Disk_5 = QemuVirtIOStorage{}.mapToStruct(params["virtio5"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio6"]; isSet { - disks.Disk_6 = QemuVirtIOStorage{}.mapToStruct(params["virtio6"].(string)) + disks.Disk_6 = QemuVirtIOStorage{}.mapToStruct(params["virtio6"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio7"]; isSet { - disks.Disk_7 = QemuVirtIOStorage{}.mapToStruct(params["virtio7"].(string)) + disks.Disk_7 = QemuVirtIOStorage{}.mapToStruct(params["virtio7"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio8"]; isSet { - disks.Disk_8 = QemuVirtIOStorage{}.mapToStruct(params["virtio8"].(string)) + disks.Disk_8 = QemuVirtIOStorage{}.mapToStruct(params["virtio8"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio9"]; isSet { - disks.Disk_9 = QemuVirtIOStorage{}.mapToStruct(params["virtio9"].(string)) + disks.Disk_9 = QemuVirtIOStorage{}.mapToStruct(params["virtio9"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio10"]; isSet { - disks.Disk_10 = QemuVirtIOStorage{}.mapToStruct(params["virtio10"].(string)) + disks.Disk_10 = QemuVirtIOStorage{}.mapToStruct(params["virtio10"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio11"]; isSet { - disks.Disk_11 = QemuVirtIOStorage{}.mapToStruct(params["virtio11"].(string)) + disks.Disk_11 = QemuVirtIOStorage{}.mapToStruct(params["virtio11"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio12"]; isSet { - disks.Disk_12 = QemuVirtIOStorage{}.mapToStruct(params["virtio12"].(string)) + disks.Disk_12 = QemuVirtIOStorage{}.mapToStruct(params["virtio12"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio13"]; isSet { - disks.Disk_13 = QemuVirtIOStorage{}.mapToStruct(params["virtio13"].(string)) + disks.Disk_13 = QemuVirtIOStorage{}.mapToStruct(params["virtio13"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio14"]; isSet { - disks.Disk_14 = QemuVirtIOStorage{}.mapToStruct(params["virtio14"].(string)) + disks.Disk_14 = QemuVirtIOStorage{}.mapToStruct(params["virtio14"].(string), linkedVmId) structPopulated = true } if _, isSet := params["virtio15"]; isSet { - disks.Disk_15 = QemuVirtIOStorage{}.mapToStruct(params["virtio15"].(string)) + disks.Disk_15 = QemuVirtIOStorage{}.mapToStruct(params["virtio15"].(string), linkedVmId) structPopulated = true } if structPopulated { @@ -280,7 +280,7 @@ func (storage *QemuVirtIOStorage) convertDataStructureMark() *qemuDiskMark { return nil } -func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { +func (QemuVirtIOStorage) mapToStruct(param string, LinkedVmId *uint) *QemuVirtIOStorage { settings := splitStringOfSettings(param) tmpCdRom := qemuCdRom{}.mapToStruct(settings) if tmpCdRom != nil { @@ -291,26 +291,26 @@ func (QemuVirtIOStorage) mapToStruct(param string) *QemuVirtIOStorage { } } - tmpDisk := qemuDisk{}.mapToStruct(settings) + tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) if tmpDisk == nil { return nil } if tmpDisk.File == "" { return &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - LinkedClone: tmpDisk.LinkedClone, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedDiskId: tmpDisk.LinkedDiskId, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, }} } return &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 2e8c24cf..6d19150b 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -15,6 +15,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { float45 := QemuDiskBandwidthMBpsLimitConcurrent(45.23) float79 := QemuDiskBandwidthMBpsLimitBurst(79.23) float99 := QemuDiskBandwidthMBpsLimitBurst(99.2) + uint1 := uint(1) uint23 := QemuDiskBandwidthIopsLimitConcurrent(23) uint34 := QemuDiskBandwidthIopsLimitConcurrent(34) uint78 := QemuDiskBandwidthIopsLimitBurst(78) @@ -1275,14 +1276,16 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"ide3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, {name: "Update Disk.Ide.Disk_X.Disk CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, @@ -1311,13 +1314,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"ide1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Ide.Disk_X.Disk MIGRATE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, - Size: 10, - Storage: "test1", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test1", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, Size: 10, @@ -1340,13 +1345,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"ide2": "test:9,backup=0,format=raw,replicate=0"}, }, {name: "Update Disk.Ide.Disk_X.Disk RESIZE DOWN LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_2: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, Size: 9, @@ -1369,13 +1376,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{}, }, {name: "Update Disk.Ide.Disk_X.Disk RESIZE UP LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 110, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Raw, Size: 11, @@ -1407,13 +1416,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"ide1": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, {name: "Update Disk.Ide.Disk_X.Disk.Format CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ Format: QemuDiskFormat_Qcow2, Size: 10, @@ -1537,14 +1548,16 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, {name: "Update Disk.Sata.Disk_X.Disk CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, @@ -1573,13 +1586,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"sata5": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Sata.Disk_X.Disk MIGRATE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, - Size: 10, - Storage: "test1", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test1", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, Size: 10, @@ -1602,13 +1617,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"sata0": "test:9,backup=0,format=raw,replicate=0"}, }, {name: "Update Disk.Sata.Disk_X.Disk RESIZE DOWN LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, Size: 9, @@ -1631,13 +1648,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{}, }, {name: "Update Disk.Sata.Disk_X.Disk RESIZE UP LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Raw, Size: 11, @@ -1669,13 +1688,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"sata3": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, {name: "Update Disk.Sata.Disk_X.Disk.Format CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_3: &QemuSataStorage{Disk: &QemuSataDisk{ Format: QemuDiskFormat_Qcow2, Size: 10, @@ -1799,14 +1820,16 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"scsi15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, {name: "Update Disk.Scsi.Disk_X.Disk CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_15: &QemuScsiStorage{Disk: &QemuScsiDisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, @@ -1835,13 +1858,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"scsi17": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.Scsi.Disk_X.Disk MIGRATE Linked Clone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, - Size: 10, - Storage: "test1", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test1", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_17: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, Size: 10, @@ -1864,13 +1889,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"scsi18": "test:9,backup=0,format=raw,replicate=0"}, }, {name: "Update Disk.Scsi.Disk_X.Disk RESIZE DOWN LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, Size: 9, @@ -1893,13 +1920,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{}, }, {name: "Update Disk.Scsi.Disk_X.Disk RESIZE UP LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Raw, Size: 11, @@ -1931,13 +1960,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"scsi21": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, {name: "Update Disk.Scsi.Disk_X.Disk.Format CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_21: &QemuScsiStorage{Disk: &QemuScsiDisk{ Format: QemuDiskFormat_Qcow2, Size: 10, @@ -2061,14 +2092,16 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"virtio15": "test:0/vm-0-disk-23.raw,aio=native,backup=0,replicate=0"}, }, {name: "Update Disk.VirtIO.Disk_X.Disk CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_15: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ AsyncIO: QemuDiskAsyncIO_Native, Format: QemuDiskFormat_Raw, @@ -2097,13 +2130,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"virtio1": "test2:0/vm-0-disk-23.raw,backup=0,replicate=0"}, }, {name: "Update Disk.VirtIO.Disk_X.Disk MIGRATE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{DiskId: 1, VmId: 100}, - Size: 10, - Storage: "test1", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test1", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, Size: 10, @@ -2126,13 +2161,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"virtio2": "test:9,backup=0,format=raw,replicate=0"}, }, {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE DOWN LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, Size: 9, @@ -2155,13 +2192,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{}, }, {name: "Update Disk.VirtIO.Disk_X.Disk RESIZE UP LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_3: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Raw, Size: 11, @@ -2193,13 +2232,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { output: map[string]interface{}{"virtio5": "test:0/vm-0-disk-23.qcow2,backup=0,replicate=0"}, }, {name: "Update Disk.VirtIO.Disk_X.Disk.Format CHANGE LinkedClone", - currentConfig: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - Format: QemuDiskFormat_Raw, - Id: 23, - LinkedClone: &QemuDiskLinkedClone{VmId: 100, DiskId: 1}, - Size: 10, - Storage: "test", - }}}}}, + currentConfig: ConfigQemu{ + LinkedVmId: 100, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Id: 23, + LinkedDiskId: &uint1, + Size: 10, + Storage: "test", + }}}}}, config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_5: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Format: QemuDiskFormat_Qcow2, Size: 10, @@ -2259,6 +2300,7 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { } func Test_ConfigQemu_mapToStruct(t *testing.T) { + uint1 := uint(1) uint2 := uint(2) uint31 := uint(31) uint47 := uint(47) @@ -2334,30 +2376,32 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, {name: "Disks Ide Disk ALL LinkedClone", input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, - output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Backup: false, - Bandwidth: QemuDiskBandwidth{ - MBps: QemuDiskBandwidthMBps{ - ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.57, Concurrent: 1.46}, - WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.55, Concurrent: 2.68}, - }, - Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, + output: &ConfigQemu{ + LinkedVmId: 110, + Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.57, Concurrent: 1.46}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.55, Concurrent: 2.68}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 12}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, + }, }, - }, - Cache: QemuDiskCache_WriteThrough, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint53, - LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, - Replicate: false, - Serial: "disk-9763", - Size: 1032, - Storage: "test2", - }}}}}, + Cache: QemuDiskCache_WriteThrough, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + LinkedDiskId: &uint1, + Replicate: false, + Serial: "disk-9763", + Size: 1032, + Storage: "test2", + }}}}}, }, {name: "Disks Ide Disk aio", input: map[string]interface{}{"ide2": "test2:100/vm-100-disk-53.qcow2,aio=io_uring"}, @@ -2812,30 +2856,32 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, {name: "Disks Sata Disk ALL LinkedClone", input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, - output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: QemuDiskAsyncIO_Native, - Backup: false, - Bandwidth: QemuDiskBandwidth{ - MBps: QemuDiskBandwidthMBps{ - ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, - }, - Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, + output: &ConfigQemu{ + LinkedVmId: 110, + Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ + AsyncIO: QemuDiskAsyncIO_Native, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, + }, }, - }, - Cache: QemuDiskCache_None, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint47, - LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", - }}}}}, + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + LinkedDiskId: &uint1, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, }, {name: "Disks Sata Disk aio", input: map[string]interface{}{"sata2": "test2:100/vm-100-disk-47.qcow2,aio=native"}, @@ -3296,32 +3342,34 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, {name: "Disks Scsi Disk ALL LinkedClone", input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, - output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: QemuDiskAsyncIO_Threads, - Backup: false, - Bandwidth: QemuDiskBandwidth{ - MBps: QemuDiskBandwidthMBps{ - ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, - }, - Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, + output: &ConfigQemu{ + LinkedVmId: 110, + Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ + AsyncIO: QemuDiskAsyncIO_Threads, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 4, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, + }, }, - }, - Cache: QemuDiskCache_WriteBack, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint2, - IOThread: true, - LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test", - }}}}}, + Cache: QemuDiskCache_WriteBack, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + IOThread: true, + LinkedDiskId: &uint1, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test", + }}}}}, }, {name: "Disks Scsi Disk aio", input: map[string]interface{}{"scsi2": "test:100/vm-100-disk-2.qcow2,aio=threads"}, @@ -3819,31 +3867,33 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }, {name: "Disks VirtIO Disk ALL LinkedClone", input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, - output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Backup: false, - Bandwidth: QemuDiskBandwidth{ - MBps: QemuDiskBandwidthMBps{ - ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, - WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, - }, - Iops: QemuDiskBandwidthIops{ - ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, - WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, + output: &ConfigQemu{ + LinkedVmId: 110, + Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + AsyncIO: QemuDiskAsyncIO_IOuring, + Backup: false, + Bandwidth: QemuDiskBandwidth{ + MBps: QemuDiskBandwidthMBps{ + ReadLimit: QemuDiskBandwidthMBpsLimit{Burst: 3.51, Concurrent: 1.51}, + WriteLimit: QemuDiskBandwidthMBpsLimit{Burst: 4.51, Concurrent: 2.51}, + }, + Iops: QemuDiskBandwidthIops{ + ReadLimit: QemuDiskBandwidthIopsLimit{Burst: 12, BurstDuration: 2, Concurrent: 10}, + WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, + }, }, - }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - Format: QemuDiskFormat_Qcow2, - Id: uint31, - IOThread: true, - LinkedClone: &QemuDiskLinkedClone{VmId: 110, DiskId: 1}, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", - }}}}}, + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + IOThread: true, + LinkedDiskId: &uint1, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + }}}}}, }, {name: "Disks VirtIO Disk aio", input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,aio=io_uring"}, From d941f39c77cafa6e9b4352e0121b638bd7e58fe7 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 4 Apr 2023 21:08:58 +0000 Subject: [PATCH 130/191] fix: API can return disk size in TerraBytes --- proxmox/config_qemu_disk.go | 12 +++++++-- proxmox/config_qemu_test.go | 52 ++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index ce2fd9c6..7caa86d5 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -419,8 +419,16 @@ func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { continue } if e[0] == "size" { - diskSize, _ := strconv.Atoi(strings.TrimSuffix(e[1], "G")) - disk.Size = uint(diskSize) + if len(e[1]) > 1 { + test := e[1][0 : len(e[1])-1] + diskSize, _ := strconv.Atoi(test) + switch e[1][len(e[1])-1:] { + case "G": + disk.Size = uint(diskSize) + case "T": + disk.Size = uint(diskSize * 1024) + } + } continue } if e[0] == "ssd" { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 6d19150b..68f7a8f3 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -2577,7 +2577,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, - {name: "Disks Ide Disk size", + {name: "Disks Ide Disk size G", input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,size=1032G"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ Backup: true, @@ -2588,6 +2588,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Ide Disk size T", + input: map[string]interface{}{"ide0": "test2:100/vm-100-disk-53.qcow2,size=2T"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + Replicate: true, + Size: 2048, + Storage: "test2", + }}}}}, + }, {name: "Disks Ide Disk ssd", input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -3061,7 +3072,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, - {name: "Disks Sata Disk size", + {name: "Disks Sata Disk size G", input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,size=32G"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ Backup: true, @@ -3072,6 +3083,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Sata Disk size T", + input: map[string]interface{}{"sata4": "test2:100/vm-100-disk-47.qcow2,size=3T"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_4: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + Replicate: true, + Size: 3072, + Storage: "test2", + }}}}}, + }, {name: "Disks Sata Disk ssd", input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -3567,7 +3589,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, - {name: "Disks Scsi Disk size", + {name: "Disks Scsi Disk size G", input: map[string]interface{}{"scsi18": "test:100/vm-100-disk-2.qcow2,size=32G"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ Backup: true, @@ -3578,6 +3600,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, + {name: "Disks Scsi Disk size T", + input: map[string]interface{}{"scsi18": "test:100/vm-100-disk-2.qcow2,size=4T"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_18: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + Replicate: true, + Size: 4096, + Storage: "test", + }}}}}, + }, {name: "Disks Scsi Disk ssd", input: map[string]interface{}{"scsi19": "test:100/vm-100-disk-2.qcow2,ssd=1"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -4095,7 +4128,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, - {name: "Disks VirtIO Disk size", + {name: "Disks VirtIO Disk size G", input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,size=32G"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ Backup: true, @@ -4106,6 +4139,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks VirtIO Disk size T", + input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,size=5T"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + Replicate: true, + Size: 5120, + Storage: "test2", + }}}}}, + }, // Disks VirtIO Passthrough {name: "Disks VirtIO Passthrough", input: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, From 0a6089b0685d265937cac96272d7688b463877f5 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Wed, 5 Apr 2023 20:55:14 +0100 Subject: [PATCH 131/191] Fixed err never used --- test/api/Authentication/authentication_apikey_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/Authentication/authentication_apikey_test.go b/test/api/Authentication/authentication_apikey_test.go index 4a7bc7b1..70922632 100644 --- a/test/api/Authentication/authentication_apikey_test.go +++ b/test/api/Authentication/authentication_apikey_test.go @@ -16,13 +16,13 @@ func Test_Root_Login_Correct_Api_Key(t *testing.T) { token := pxapi.ApiToken{TokenId: "testing", Comment: "This is a test", Expire: 0, Privsep: false} - value, err := user.CreateApiToken(Test.GetClient(), token) + value, _ := user.CreateApiToken(Test.GetClient(), token) NewTest := api_test.Test{} NewTest.CreateClient() NewTest.GetClient().SetAPIToken("root@pam!testing", value) - _, err = NewTest.GetClient().GetVersion() + _, err := NewTest.GetClient().GetVersion() require.NoError(t, err) user.DeleteApiToken(Test.GetClient(), token) From c11acf162bb40a8bf67972465c535bca4a728252 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:27:09 +0000 Subject: [PATCH 132/191] refactor: change custom type to uint --- proxmox/config_qemu_disk.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 7caa86d5..f1e06967 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -372,7 +372,7 @@ func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { } if e[0] == "iops_rd_max_length" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.BurstDuration = QemuDiskBandwidthBurstDuration(tmp) + disk.Bandwidth.Iops.ReadLimit.BurstDuration = uint(tmp) } if e[0] == "iops_wr" { tmp, _ := strconv.Atoi(e[1]) @@ -384,7 +384,7 @@ func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { } if e[0] == "iops_wr_max_length" { tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.BurstDuration = QemuDiskBandwidthBurstDuration(tmp) + disk.Bandwidth.Iops.WriteLimit.BurstDuration = uint(tmp) } if e[0] == "iothread" { disk.IOThread, _ = strconv.ParseBool(e[1]) @@ -507,9 +507,6 @@ func (bandwidth QemuDiskBandwidth) Validate() error { return bandwidth.Iops.Validate() } -// burst duration in seconds -type QemuDiskBandwidthBurstDuration uint - type QemuDiskBandwidthIops struct { ReadLimit QemuDiskBandwidthIopsLimit `json:"read,omitempty"` WriteLimit QemuDiskBandwidthIopsLimit `json:"write,omitempty"` @@ -524,9 +521,9 @@ func (iops QemuDiskBandwidthIops) Validate() error { } type QemuDiskBandwidthIopsLimit struct { - Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = unlimited - BurstDuration QemuDiskBandwidthBurstDuration `json:"burst_duration,omitempty"` - Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited + Burst QemuDiskBandwidthIopsLimitBurst `json:"burst,omitempty"` // 0 = unlimited + BurstDuration uint `json:"burst_duration,omitempty"` // burst duration in seconds + Concurrent QemuDiskBandwidthIopsLimitConcurrent `json:"concurrent,omitempty"` // 0 = unlimited } func (limit QemuDiskBandwidthIopsLimit) Validate() (err error) { From df891852765487d9e8cdfee5105433b51eba940f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 6 Apr 2023 18:34:55 +0000 Subject: [PATCH 133/191] refactor: use map instad of 2D string array --- proxmox/config_qemu_disk.go | 213 +++++++++++++---------------- proxmox/config_qemu_disk_ide.go | 10 +- proxmox/config_qemu_disk_sata.go | 10 +- proxmox/config_qemu_disk_scsi.go | 10 +- proxmox/config_qemu_disk_test.go | 8 +- proxmox/config_qemu_disk_virtio.go | 10 +- proxmox/util.go | 15 +- proxmox/util_test.go | 14 +- 8 files changed, 147 insertions(+), 143 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index f1e06967..8b31db7f 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -87,41 +87,34 @@ type qemuCdRom struct { Size string } -func (qemuCdRom) mapToStruct(settings [][]string) *qemuCdRom { +func (qemuCdRom) mapToStruct(diskData string, settings map[string]interface{}) *qemuCdRom { var isCdRom bool - for _, e := range settings { - if e[0] == "media" { - if e[1] == "cdrom" { - isCdRom = true - break - } - } + if setting, isSet := settings["media"]; isSet { + isCdRom = setting.(string) == "cdrom" } if !isCdRom { return nil } - if settings[0][0] == "none" { + if _, isSet := settings["none"]; isSet { return &qemuCdRom{CdRom: true} } - if settings[0][0] == "cdrom" { + if _, isSet := settings["cdrom"]; isSet { return &qemuCdRom{CdRom: true, Passthrough: true} } - tmpStorage := strings.Split(settings[0][0], ":") + tmpStorage := strings.Split(diskData, ":") if len(tmpStorage) > 1 { - tmpFile := strings.Split(settings[0][0], "/") + tmpFile := strings.Split(diskData, "/") if len(tmpFile) == 2 { tmpFileType := strings.Split(tmpFile[1], ".") if len(tmpFileType) > 1 { fileType := QemuDiskFormat(tmpFileType[len(tmpFileType)-1]) if fileType == "iso" { - for _, e := range settings { - if e[0] == "size" { - return &qemuCdRom{ - CdRom: true, - Storage: tmpStorage[0], - File: tmpFile[1], - Size: e[1], - } + if setting, isSet := settings["size"]; isSet { + return &qemuCdRom{ + CdRom: true, + Storage: tmpStorage[0], + File: tmpFile[1], + Size: setting.(string), } } } else { @@ -300,18 +293,15 @@ func (disk qemuDisk) mapToApiValues(vmID, LinkedVmId uint, currentStorage string } // Maps all the disk related settings to our own data structure. -func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { - if len(settings) == 0 { - return nil - } +func (qemuDisk) mapToStruct(diskData string, settings map[string]interface{}, linkedVmId *uint) *qemuDisk { disk := qemuDisk{Backup: true} - if settings[0][0][0:1] == "/" { - disk.File = settings[0][0] + if diskData[0:1] == "/" { + disk.File = diskData } else { // storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2 // storage:100/vm-100-disk-0.qcow2 - diskAndPath := strings.Split(settings[0][0], ":") + diskAndPath := strings.Split(diskData, ":") disk.Storage = diskAndPath[0] if len(diskAndPath) == 2 { pathParts := strings.Split(diskAndPath[1], "/") @@ -340,101 +330,94 @@ func (qemuDisk) mapToStruct(settings [][]string, linkedVmId *uint) *qemuDisk { } } + if len(settings) == 0 { + return nil + } + // Replicate defaults to true disk.Replicate = true - for _, e := range settings { - if e[0] == "aio" { - disk.AsyncIO = QemuDiskAsyncIO(e[1]) - continue - } - if e[0] == "backup" { - disk.Backup, _ = strconv.ParseBool(e[1]) - continue - } - if e[0] == "cache" { - disk.Cache = QemuDiskCache(e[1]) - continue - } - if e[0] == "discard" { - if e[1] == "on" { - disk.Discard = true - } - continue - } - if e[0] == "iops_rd" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) - } - if e[0] == "iops_rd_max" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) - } - if e[0] == "iops_rd_max_length" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.ReadLimit.BurstDuration = uint(tmp) - } - if e[0] == "iops_wr" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) - } - if e[0] == "iops_wr_max" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) - } - if e[0] == "iops_wr_max_length" { - tmp, _ := strconv.Atoi(e[1]) - disk.Bandwidth.Iops.WriteLimit.BurstDuration = uint(tmp) - } - if e[0] == "iothread" { - disk.IOThread, _ = strconv.ParseBool(e[1]) - continue - } - if e[0] == "mbps_rd" { - tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.MBps.ReadLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) - } - if e[0] == "mbps_rd_max" { - tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.MBps.ReadLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) - } - if e[0] == "mbps_wr" { - tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.MBps.WriteLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) - } - if e[0] == "mbps_wr_max" { - tmp, _ := strconv.ParseFloat(e[1], 32) - disk.Bandwidth.MBps.WriteLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) - } - if e[0] == "replicate" { - disk.Replicate, _ = strconv.ParseBool(e[1]) - continue - } - if e[0] == "ro" { - disk.ReadOnly, _ = strconv.ParseBool(e[1]) - continue - } - if e[0] == "serial" { - disk.Serial = QemuDiskSerial(e[1]) - continue + if value, isSet := settings["aio"]; isSet { + disk.AsyncIO = QemuDiskAsyncIO(value.(string)) + } + if value, isSet := settings["backup"]; isSet { + disk.Backup, _ = strconv.ParseBool(value.(string)) + } + if value, isSet := settings["cache"]; isSet { + disk.Cache = QemuDiskCache(value.(string)) + } + if value, isSet := settings["discard"]; isSet { + if value.(string) == "on" { + disk.Discard = true } - if e[0] == "size" { - if len(e[1]) > 1 { - test := e[1][0 : len(e[1])-1] - diskSize, _ := strconv.Atoi(test) - switch e[1][len(e[1])-1:] { - case "G": - disk.Size = uint(diskSize) - case "T": - disk.Size = uint(diskSize * 1024) - } + } + if value, isSet := settings["iops_rd"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.ReadLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) + } + if value, isSet := settings["iops_rd_max"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.ReadLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) + } + if value, isSet := settings["iops_rd_max_length"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.ReadLimit.BurstDuration = uint(tmp) + } + if value, isSet := settings["iops_wr"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.WriteLimit.Concurrent = QemuDiskBandwidthIopsLimitConcurrent(tmp) + } + if value, isSet := settings["iops_wr_max"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.WriteLimit.Burst = QemuDiskBandwidthIopsLimitBurst(tmp) + } + if value, isSet := settings["iops_wr_max_length"]; isSet { + tmp, _ := strconv.Atoi(value.(string)) + disk.Bandwidth.Iops.WriteLimit.BurstDuration = uint(tmp) + } + if value, isSet := settings["iothread"]; isSet { + disk.IOThread, _ = strconv.ParseBool(value.(string)) + } + if value, isSet := settings["mbps_rd"]; isSet { + tmp, _ := strconv.ParseFloat(value.(string), 32) + disk.Bandwidth.MBps.ReadLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) + } + if value, isSet := settings["mbps_rd_max"]; isSet { + tmp, _ := strconv.ParseFloat(value.(string), 32) + disk.Bandwidth.MBps.ReadLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) + } + if value, isSet := settings["mbps_wr"]; isSet { + tmp, _ := strconv.ParseFloat(value.(string), 32) + disk.Bandwidth.MBps.WriteLimit.Concurrent = QemuDiskBandwidthMBpsLimitConcurrent(math.Round(tmp*100) / 100) + } + if value, isSet := settings["mbps_wr_max"]; isSet { + tmp, _ := strconv.ParseFloat(value.(string), 32) + disk.Bandwidth.MBps.WriteLimit.Burst = QemuDiskBandwidthMBpsLimitBurst(math.Round(tmp*100) / 100) + } + if value, isSet := settings["replicate"]; isSet { + disk.Replicate, _ = strconv.ParseBool(value.(string)) + } + if value, isSet := settings["ro"]; isSet { + disk.ReadOnly, _ = strconv.ParseBool(value.(string)) + } + if value, isSet := settings["serial"]; isSet { + disk.Serial = QemuDiskSerial(value.(string)) + } + if value, isSet := settings["size"]; isSet { + sizeString := value.(string) + if len(sizeString) > 1 { + diskSize, _ := strconv.Atoi(sizeString[0 : len(sizeString)-1]) + switch sizeString[len(sizeString)-1:] { + case "G": + disk.Size = uint(diskSize) + case "T": + disk.Size = uint(diskSize * 1024) } - continue - } - if e[0] == "ssd" { - disk.EmulateSSD, _ = strconv.ParseBool(e[1]) } } + if value, isSet := settings["ssd"]; isSet { + disk.EmulateSSD, _ = strconv.ParseBool(value.(string)) + } return &disk } diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index d0746259..ed019ae3 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -1,6 +1,9 @@ package proxmox -import "strconv" +import ( + "strconv" + "strings" +) type QemuIdeDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` @@ -205,8 +208,9 @@ func (storage *QemuIdeStorage) convertDataStructureMark() *qemuDiskMark { } func (QemuIdeStorage) mapToStruct(param string, LinkedVmId *uint) *QemuIdeStorage { + diskData, _, _ := strings.Cut(param, ",") settings := splitStringOfSettings(param) - tmpCdRom := qemuCdRom{}.mapToStruct(settings) + tmpCdRom := qemuCdRom{}.mapToStruct(diskData, settings) if tmpCdRom != nil { if tmpCdRom.CdRom { return &QemuIdeStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} @@ -215,7 +219,7 @@ func (QemuIdeStorage) mapToStruct(param string, LinkedVmId *uint) *QemuIdeStorag } } - tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) + tmpDisk := qemuDisk{}.mapToStruct(diskData, settings, LinkedVmId) if tmpDisk == nil { return nil } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index 3e1cb7db..d1c4b584 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -1,6 +1,9 @@ package proxmox -import "strconv" +import ( + "strconv" + "strings" +) type QemuSataDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` @@ -217,8 +220,9 @@ func (storage *QemuSataStorage) convertDataStructureMark() *qemuDiskMark { } func (QemuSataStorage) mapToStruct(param string, LinkedVmId *uint) *QemuSataStorage { + diskData, _, _ := strings.Cut(param, ",") settings := splitStringOfSettings(param) - tmpCdRom := qemuCdRom{}.mapToStruct(settings) + tmpCdRom := qemuCdRom{}.mapToStruct(diskData, settings) if tmpCdRom != nil { if tmpCdRom.CdRom { return &QemuSataStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} @@ -227,7 +231,7 @@ func (QemuSataStorage) mapToStruct(param string, LinkedVmId *uint) *QemuSataStor } } - tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) + tmpDisk := qemuDisk{}.mapToStruct(diskData, settings, LinkedVmId) if tmpDisk == nil { return nil } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 43b83be8..3ad5a1ea 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -1,6 +1,9 @@ package proxmox -import "strconv" +import ( + "strconv" + "strings" +) type QemuScsiDisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` @@ -375,8 +378,9 @@ func (storage *QemuScsiStorage) convertDataStructureMark() *qemuDiskMark { } func (QemuScsiStorage) mapToStruct(param string, LinkedVmId *uint) *QemuScsiStorage { + diskData, _, _ := strings.Cut(param, ",") settings := splitStringOfSettings(param) - tmpCdRom := qemuCdRom{}.mapToStruct(settings) + tmpCdRom := qemuCdRom{}.mapToStruct(diskData, settings) if tmpCdRom != nil { if tmpCdRom.CdRom { return &QemuScsiStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} @@ -385,7 +389,7 @@ func (QemuScsiStorage) mapToStruct(param string, LinkedVmId *uint) *QemuScsiStor } } - tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) + tmpDisk := qemuDisk{}.mapToStruct(diskData, settings, LinkedVmId) if tmpDisk == nil { return nil } diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 167b8f07..2f5c23ac 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -90,24 +90,24 @@ func Test_QemuCloudInitDisk_Validate(t *testing.T) { func Test_qemuDisk_mapToStruct(t *testing.T) { tests := []struct { name string - input [][]string + input string linkedVmId uint output uint }{ {name: "Don't Update LinkedVmId", - input: [][]string{{"storage:100/vm-100-disk-0.qcow2"}}, + input: "storage:100/vm-100-disk-0.qcow2", linkedVmId: 110, output: 110, }, {name: "Update LinkedVmId", - input: [][]string{{"storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2"}}, + input: "storage:110/base-110-disk-1.qcow2/100/vm-100-disk-0.qcow2", output: 110, }, } for _, test := range tests { t.Run(test.name, func(*testing.T) { linkedVmId := uint(test.linkedVmId) - qemuDisk{}.mapToStruct(test.input, &linkedVmId) + qemuDisk{}.mapToStruct(test.input, nil, &linkedVmId) require.Equal(t, test.output, linkedVmId, test.name) }) } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 95485877..4962d5e2 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -1,6 +1,9 @@ package proxmox -import "strconv" +import ( + "strconv" + "strings" +) type QemuVirtIODisk struct { AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` @@ -281,8 +284,9 @@ func (storage *QemuVirtIOStorage) convertDataStructureMark() *qemuDiskMark { } func (QemuVirtIOStorage) mapToStruct(param string, LinkedVmId *uint) *QemuVirtIOStorage { + diskData, _, _ := strings.Cut(param, ",") settings := splitStringOfSettings(param) - tmpCdRom := qemuCdRom{}.mapToStruct(settings) + tmpCdRom := qemuCdRom{}.mapToStruct(diskData, settings) if tmpCdRom != nil { if tmpCdRom.CdRom { return &QemuVirtIOStorage{CdRom: QemuCdRom{}.mapToStruct(*tmpCdRom)} @@ -291,7 +295,7 @@ func (QemuVirtIOStorage) mapToStruct(param string, LinkedVmId *uint) *QemuVirtIO } } - tmpDisk := qemuDisk{}.mapToStruct(settings, LinkedVmId) + tmpDisk := qemuDisk{}.mapToStruct(diskData, settings, LinkedVmId) if tmpDisk == nil { return nil } diff --git a/proxmox/util.go b/proxmox/util.go index f1c4fcfe..400f91e6 100644 --- a/proxmox/util.go +++ b/proxmox/util.go @@ -216,11 +216,16 @@ func keyExists(array []interface{}, key string) (existence bool) { return false } -func splitStringOfSettings(settings string) (settingArray [][]string) { +func splitStringOfSettings(settings string) map[string]interface{} { settingValuePairs := strings.Split(settings, ",") - settingArray = make([][]string, len(settingValuePairs)) - for i, e := range settingValuePairs { - settingArray[i] = strings.SplitN(e, "=", 2) + settingMap := map[string]interface{}{} + for _, e := range settingValuePairs { + keyValuePair := strings.SplitN(e, "=", 2) + var value string + if len(keyValuePair) == 2 { + value = keyValuePair[1] + } + settingMap[keyValuePair[0]] = value } - return + return settingMap } diff --git a/proxmox/util_test.go b/proxmox/util_test.go index db842767..1ac4211c 100644 --- a/proxmox/util_test.go +++ b/proxmox/util_test.go @@ -55,16 +55,16 @@ func Test_keyExists(t *testing.T) { func Test_splitStringOfSettings(t *testing.T) { testData := []struct { Input string - Output [][]string + Output map[string]interface{} }{ { Input: "setting=a,thing=b,randomString,doubleTest=value=equals,object=test", - Output: [][]string{ - {"setting", "a"}, - {"thing", "b"}, - {"randomString"}, - {"doubleTest", "value=equals"}, - {"object", "test"}, + Output: map[string]interface{}{ + "setting": "a", + "thing": "b", + "randomString": "", + "doubleTest": "value=equals", + "object": "test", }, }, } From 30fe7d2dd7fdbb9ab0f78f2d26950090846c1418 Mon Sep 17 00:00:00 2001 From: mleone87 <807457+mleone87@users.noreply.github.com> Date: Tue, 11 Apr 2023 23:38:24 +0200 Subject: [PATCH 134/191] feat: upgrade go to 1.19 --- go.mod | 8 ++++---- go.sum | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 8de2c3bd..ff678567 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,15 @@ module github.com/Telmate/proxmox-api-go -go 1.18 +go 1.19 require ( - github.com/spf13/cobra v1.5.0 - github.com/stretchr/testify v1.8.0 + github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.8.2 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 00ef3216..0df3271b 100644 --- a/go.sum +++ b/go.sum @@ -2,24 +2,24 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From bff8fdd044fa9028632f191c3423742c93073fe5 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Thu, 13 Apr 2023 16:18:24 +0100 Subject: [PATCH 135/191] Added Template download provisioner --- Vagrantfile | 9 ++++++++- scripts/vagrant-get-container-template.sh | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 scripts/vagrant-get-container-template.sh diff --git a/Vagrantfile b/Vagrantfile index 7c4d81fd..017f33f3 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -11,10 +11,17 @@ Vagrant.configure("2") do |config| host: 8006 # install and configure proxmox - config.vm.provision "shell", + config.vm.provision "Bootstrap System", + type: "shell", privileged: true, path: './scripts/vagrant-bootstrap.sh' + config.vm.provision "Import LXC Template", + type: "shell", + privileged: true, + path: './scripts/vagrant-get-container-template.sh', + run: "always" + config.vm.provider :virtualbox do |vb| vb.memory = 2048 vb.cpus = 2 diff --git a/scripts/vagrant-get-container-template.sh b/scripts/vagrant-get-container-template.sh new file mode 100644 index 00000000..a2de7d41 --- /dev/null +++ b/scripts/vagrant-get-container-template.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +pveam download local alpine-3.17-default_20221129_amd64.tar.xz \ No newline at end of file From 6c5561c5c454543c83f78c6c7657cf84aa757360 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Thu, 13 Apr 2023 16:19:03 +0100 Subject: [PATCH 136/191] Fixed broken Qemu clone test --- test/api/Qemu/qemu_clone_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/Qemu/qemu_clone_test.go b/test/api/Qemu/qemu_clone_test.go index 93d85191..20345bb0 100644 --- a/test/api/Qemu/qemu_clone_test.go +++ b/test/api/Qemu/qemu_clone_test.go @@ -9,7 +9,7 @@ import ( ) func _create_clone_vmref() (ref *pxapi.VmRef) { - ref = pxapi.NewVmRef(100) + ref = pxapi.NewVmRef(101) ref.SetNode("pve") ref.SetVmType("qemu") return ref From 25faab286fd7e4a91965946d635abd09ff4d91a2 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Thu, 13 Apr 2023 16:19:31 +0100 Subject: [PATCH 137/191] Added Lxc CRUD test --- test/api/Lxc/lxc_create_update_delete_test.go | 56 +++++++++++++++++++ test/api/Lxc/shared_test.go | 52 +++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/api/Lxc/lxc_create_update_delete_test.go create mode 100644 test/api/Lxc/shared_test.go diff --git a/test/api/Lxc/lxc_create_update_delete_test.go b/test/api/Lxc/lxc_create_update_delete_test.go new file mode 100644 index 00000000..d3940ad4 --- /dev/null +++ b/test/api/Lxc/lxc_create_update_delete_test.go @@ -0,0 +1,56 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Create_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + config := _create_lxc_spec(true) + + err := config.CreateLxc(_create_vmref(), Test.GetClient()) + require.NoError(t, err) +} + +func Test_Lxc_Container_Is_Added(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigLxcFromApi(_create_vmref(), Test.GetClient()) + + require.Equal(t, "alpine", config.OsType) +} + +func Test_Update_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigLxcFromApi(_create_vmref(), Test.GetClient()) + + config.Cores = 2 + + err := config.UpdateConfig(_create_vmref(), Test.GetClient()) + + require.NoError(t, err) +} + +func Test_Lxc_Container_Is_Updated(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config, _ := pxapi.NewConfigLxcFromApi(_create_vmref(), Test.GetClient()) + require.Equal(t, 2, config.Cores) +} + +func Test_Remove_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + _, err := Test.GetClient().DeleteVm(_create_vmref()) + + require.NoError(t, err) +} diff --git a/test/api/Lxc/shared_test.go b/test/api/Lxc/shared_test.go new file mode 100644 index 00000000..55623cc1 --- /dev/null +++ b/test/api/Lxc/shared_test.go @@ -0,0 +1,52 @@ +package api_test + +import ( + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +func _create_vmref() (ref *pxapi.VmRef) { + ref = pxapi.NewVmRef(200) + ref.SetNode("pve") + ref.SetVmType("lxc") + return ref +} + +func _create_lxc_spec(network bool) pxapi.ConfigLxc { + + disks := make(pxapi.QemuDevices) + disks[0] = make(map[string]interface{}) + disks[0]["type"] = "virtio" + disks[0]["storage"] = "local" + disks[0]["size"] = "8G" + + networks := make(pxapi.QemuDevices) + networks[0] = make(map[string]interface{}) + networks[0]["bridge"] = "vmbr0" + networks[0]["firewall"] = "true" + networks[0]["name"] = "nnet0" + + config := pxapi.ConfigLxc{ + Hostname: "test-lxc01", + Cores: 1, + Memory: 128, + Password: "SuperSecretPassword", + Ostemplate: "local:vztmpl/alpine-3.17-default_20221129_amd64.tar.xz", + Storage: "local", + RootFs: disks[0], + Networks: networks, + Arch: "amd64", + CMode: "tty", + Console: true, + CPULimit: 0, + CPUUnits: 1024, + OnBoot: false, + Protection: false, + Start: false, + Swap: 512, + Template: false, + Tty: 2, + Unprivileged: false, + } + + return config +} From b235b12b75dc2bc4d08b342b37e52d52f4d17ff6 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Thu, 13 Apr 2023 16:23:43 +0100 Subject: [PATCH 138/191] Added Lxc Start/Stop tests --- test/api/Lxc/lxc_start_test.go | 38 ++++++++++++++++++++++++++++++++++ test/api/Lxc/shared_test.go | 4 ---- 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 test/api/Lxc/lxc_start_test.go diff --git a/test/api/Lxc/lxc_start_test.go b/test/api/Lxc/lxc_start_test.go new file mode 100644 index 00000000..64b4b6a9 --- /dev/null +++ b/test/api/Lxc/lxc_start_test.go @@ -0,0 +1,38 @@ +package api_test + +import ( + "testing" + + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Start_Stop_Lxc_Container_Setup(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + config := _create_lxc_spec(false) + config.CreateLxc(_create_vmref(), Test.GetClient()) +} + +func Test_Start_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := Test.GetClient().StartVm(_create_vmref()) + require.NoError(t, err) +} + +func Test_Stop_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + + _, err := Test.GetClient().StopVm(_create_vmref()) + require.NoError(t, err) +} + +func Test_Start_Stop_Lxc_Container_Cleanup(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + Test.GetClient().DeleteVm(_create_vmref()) +} diff --git a/test/api/Lxc/shared_test.go b/test/api/Lxc/shared_test.go index 55623cc1..b967b130 100644 --- a/test/api/Lxc/shared_test.go +++ b/test/api/Lxc/shared_test.go @@ -20,10 +20,6 @@ func _create_lxc_spec(network bool) pxapi.ConfigLxc { disks[0]["size"] = "8G" networks := make(pxapi.QemuDevices) - networks[0] = make(map[string]interface{}) - networks[0]["bridge"] = "vmbr0" - networks[0]["firewall"] = "true" - networks[0]["name"] = "nnet0" config := pxapi.ConfigLxc{ Hostname: "test-lxc01", From c8e3d98d40ed574a7386c2280077034216820e66 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 2 May 2023 18:41:22 +0000 Subject: [PATCH 139/191] Make func private --- proxmox/config_qemu.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 14340834..c828d34b 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -91,7 +91,7 @@ type ConfigQemu struct { // Create - Tell Proxmox API to make the VM func (config ConfigQemu) Create(vmr *VmRef, client *Client) (err error) { - _, err = config.SetAdvanced(nil, false, vmr, client) + _, err = config.setAdvanced(nil, false, vmr, client) return } @@ -697,7 +697,7 @@ func (newConfig ConfigQemu) Update(rebootIfNeeded bool, vmr *VmRef, client *Clie if err != nil { return } - return newConfig.SetAdvanced(currentConfig, rebootIfNeeded, vmr, client) + return newConfig.setAdvanced(currentConfig, rebootIfNeeded, vmr, client) } func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) { @@ -712,7 +712,7 @@ func (config *ConfigQemu) setVmr(vmr *VmRef) (err error) { return } -func (newConfig ConfigQemu) SetAdvanced(currentConfig *ConfigQemu, rebootIfNeeded bool, vmr *VmRef, client *Client) (rebootRequired bool, err error) { +func (newConfig ConfigQemu) setAdvanced(currentConfig *ConfigQemu, rebootIfNeeded bool, vmr *VmRef, client *Client) (rebootRequired bool, err error) { err = newConfig.setVmr(vmr) if err != nil { return From e1851266e38be9ecbb0d9d7d62257eba55a9bdf2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 2 May 2023 19:12:41 +0000 Subject: [PATCH 140/191] Restore Deprecated functions --- proxmox/config_qemu.go | 106 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index c828d34b..e44fbb37 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -99,19 +99,110 @@ func (config ConfigQemu) Create(vmr *VmRef, client *Client) (err error) { // // CreateVm - Tell Proxmox API to make the VM func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { - err = config.setVmr(vmr) - if err != nil { - return + if config.HasCloudInit() { + return fmt.Errorf("cloud-init parameters only supported on clones or updates") + } + vmr.SetVmType("qemu") + + params := map[string]interface{}{ + "vmid": vmr.vmId, + "name": config.Name, + "startup": config.Startup, + "agent": config.Agent, + "ostype": config.QemuOs, + "sockets": config.QemuSockets, + "cores": config.QemuCores, + "cpu": config.QemuCpu, + "hotplug": config.Hotplug, + "memory": config.Memory, + "boot": config.Boot, + "description": config.Description, + "tags": config.Tags, + "machine": config.Machine, + "args": config.Args, + } + + if config.QemuNuma != nil { + params["numa"] = *config.QemuNuma + } + + if config.QemuKVM != nil { + params["kvm"] = *config.QemuKVM + } + + if config.Tablet != nil { + params["tablet"] = *config.Tablet + } + + if config.Onboot != nil { + params["onboot"] = *config.Onboot + } + + if config.QemuIso != "" { + params["ide2"] = config.QemuIso + ",media=cdrom" + } + + if config.Bios != "" { + params["bios"] = config.Bios + } + + if config.Balloon >= 1 { + params["balloon"] = config.Balloon + } + + if config.QemuVcpus >= 1 { + params["vcpus"] = config.QemuVcpus + } + + if vmr.pool != "" { + params["pool"] = vmr.pool } - err = config.Validate() + if config.Boot != "" { + params["boot"] = config.Boot + } + if config.BootDisk != "" { + params["bootdisk"] = config.BootDisk + } + + if config.Scsihw != "" { + params["scsihw"] = config.Scsihw + } + + err = config.CreateQemuMachineParam(params) if err != nil { - return + log.Printf("[ERROR] %q", err) + } + + // Create disks config. + config.CreateQemuDisksParams(params, false) + + // Create EFI disk + config.CreateQemuEfiParams(params) + + // Create vga config. + vgaParam := QemuDeviceParam{} + vgaParam = vgaParam.createDeviceParam(config.QemuVga, nil) + if len(vgaParam) > 0 { + params["vga"] = strings.Join(vgaParam, ",") } - _, params, err := config.mapToApiValues(ConfigQemu{}) + + // Create networks config. + config.CreateQemuNetworksParams(params) + + // Create ipconfig. + err = config.CreateIpconfigParams(params) if err != nil { - return + log.Printf("[ERROR] %q", err) } + // Create serial interfaces + config.CreateQemuSerialsParams(params) + + config.CreateQemuPCIsParams(params) + + // Create usb interfaces + config.CreateQemuUsbsParams(params) + exitStatus, err := client.CreateQemuVm(vmr.node, params) if err != nil { return fmt.Errorf("error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params) @@ -984,7 +1075,6 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { configParamsDisk := map[string]interface{}{ "vmid": vmr.vmId, } - // TODO keep going if error= config.CreateQemuDisksParams(configParamsDisk, false) // TODO keep going if error= _, err = client.createVMDisks(vmr.node, configParamsDisk) From 9fa35651591aca9b66656126907e1edcec558460 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 2 May 2023 21:03:09 +0000 Subject: [PATCH 141/191] Remove unused variables --- proxmox/config_qemu.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index e44fbb37..2f3e8d5b 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -1164,16 +1164,12 @@ func NewConfigQemuFromJson(input []byte) (config *ConfigQemu, err error) { } var ( - rxIso = regexp.MustCompile(`(.*?),media`) rxDeviceID = regexp.MustCompile(`\d+`) - rxDiskName = regexp.MustCompile(`(virtio|scsi|ide|sata)\d+`) - rxDiskType = regexp.MustCompile(`\D+`) rxUnusedDiskName = regexp.MustCompile(`^(unused)\d+`) rxNicName = regexp.MustCompile(`net\d+`) rxMpName = regexp.MustCompile(`mp\d+`) rxSerialName = regexp.MustCompile(`serial\d+`) rxUsbName = regexp.MustCompile(`usb\d+`) - rxDiskPath = regexp.MustCompile(`^\/dev\/.*`) rxPCIName = regexp.MustCompile(`hostpci\d+`) rxIpconfigName = regexp.MustCompile(`ipconfig\d+`) ) From 0217b72c277fc4b2612e55cf34f42e9055f6b6e0 Mon Sep 17 00:00:00 2001 From: jingquanShe <1031718641@qq.com> Date: Thu, 4 May 2023 09:55:00 +0800 Subject: [PATCH 142/191] =?UTF-8?q?=E2=9C=A8=20feat(client):=20add=20Uploa?= =?UTF-8?q?dLargeFile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- proxmox/client.go | 66 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index b1edab45..9a3b4a73 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -138,7 +138,7 @@ func (c *Client) GetJsonRetryable(url string, data *map[string]interface{}, trie if strings.Contains(statErr.Error(), "500 no such resource") { return statErr } - //fmt.Printf("[DEBUG][GetJsonRetryable] Sleeping for %d seconds before asking url %s", ii+1, url) + // fmt.Printf("[DEBUG][GetJsonRetryable] Sleeping for %d seconds before asking url %s", ii+1, url) time.Sleep(time.Duration(ii+1) * time.Second) } return statErr @@ -153,7 +153,7 @@ func (c *Client) GetNodeList() (list map[string]interface{}, err error) { // For resource types that can be in a disabled state, disabled resources // will not be returned func (c *Client) GetResourceList(resourceType string) (list map[string]interface{}, err error) { - var endpoint = "/cluster/resources" + endpoint := "/cluster/resources" if resourceType != "" { endpoint = fmt.Sprintf("%s?type=%s", endpoint, resourceType) } @@ -443,8 +443,10 @@ func (c *Client) WaitForCompletion(taskResponse map[string]interface{}) (waitExi return "", fmt.Errorf("Wait timeout for:" + taskUpid) } -var rxTaskNode = regexp.MustCompile("UPID:(.*?):") -var rxExitStatusSuccess = regexp.MustCompile(`^(OK|WARNINGS)`) +var ( + rxTaskNode = regexp.MustCompile("UPID:(.*?):") + rxExitStatusSuccess = regexp.MustCompile(`^(OK|WARNINGS)`) +) func (c *Client) GetTaskExitstatus(taskUpid string) (exitStatus interface{}, err error) { node := rxTaskNode.FindStringSubmatch(taskUpid)[1] @@ -518,7 +520,7 @@ func (c *Client) DeleteVmParams(vmr *VmRef, params map[string]interface{}) (exit return "", err } - //Remove HA if required + // Remove HA if required if vmr.haState != "" { url := fmt.Sprintf("/cluster/ha/resources/%d", vmr.vmId) resp, err := c.session.Delete(url, nil, nil) @@ -616,7 +618,6 @@ func (c *Client) CreateLxcContainer(node string, vmParams map[string]interface{} } func (c *Client) CloneLxcContainer(vmr *VmRef, vmParams map[string]interface{}) (exitStatus string, err error) { - reqbody := ParamsToBody(vmParams) url := fmt.Sprintf("/nodes/%s/lxc/%s/clone", vmr.node, vmParams["vmid"]) resp, err := c.session.Post(url, nil, nil, &reqbody) @@ -880,7 +881,6 @@ func (c *Client) CreateVMDisk( fullDiskName string, diskParams map[string]interface{}, ) error { - reqbody := ParamsToBody(diskParams) url := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName) resp, err := c.session.Post(url, nil, nil, &reqbody) @@ -936,7 +936,6 @@ func (c *Client) createVMDisks( // CreateNewDisk - This method allows simpler disk creation for direct client users // It should work for any existing container and virtual machine func (c *Client) CreateNewDisk(vmr *VmRef, disk string, volume string) (exitStatus interface{}, err error) { - reqbody := ParamsToBody(map[string]interface{}{disk: volume}) url := fmt.Sprintf("/nodes/%s/%s/%d/config", vmr.node, vmr.vmType, vmr.vmId) resp, err := c.session.Put(url, nil, nil, &reqbody) @@ -1332,6 +1331,47 @@ func (c *Client) Upload(node string, storage string, contentType string, filenam return nil } +func (c *Client) UploadLargeFile(node string, storage string, contentType string, filename string, filesize int64, file io.Reader) error { + var contentLength int64 + + var body io.Reader + var mimetype string + var err error + body, mimetype, contentLength, err = createStreamedUploadBody(contentType, filename, filesize, file) + if err != nil { + return err + } + + url := fmt.Sprintf("%s/nodes/%s/storage/%s/upload", c.session.ApiUrl, node, storage) + headers := c.session.Headers.Clone() + headers.Add("Content-Type", mimetype) + headers.Add("Accept", "application/json") + req, err := c.session.NewRequest(http.MethodPost, url, &headers, body) + if err != nil { + return err + } + + req.ContentLength = contentLength + + resp, err := c.session.Do(req) + if err != nil { + return err + } + + taskResponse, err := ResponseJSON(resp) + if err != nil { + return err + } + exitStatus, err := c.WaitForCompletion(taskResponse) + if err != nil { + return err + } + if exitStatus != exitStatusSuccess { + return fmt.Errorf("moving file to destination failed: %v", exitStatus) + } + return nil +} + func createUploadBody(contentType string, filename string, r io.Reader) (io.Reader, string, error) { var buf bytes.Buffer w := multipart.NewWriter(&buf) @@ -1476,7 +1516,6 @@ func (c *Client) ReadVMHA(vmr *VmRef) (err error) { } } return - } func (c *Client) UpdateVMHA(vmr *VmRef, haState string, haGroup string) (exitStatus interface{}, err error) { @@ -1485,7 +1524,7 @@ func (c *Client) UpdateVMHA(vmr *VmRef, haState string, haGroup string) (exitSta return } - //Remove HA + // Remove HA if haState == "" { url := fmt.Sprintf("/cluster/ha/resources/%d", vmr.vmId) resp, err := c.session.Delete(url, nil, nil) @@ -1502,7 +1541,7 @@ func (c *Client) UpdateVMHA(vmr *VmRef, haState string, haGroup string) (exitSta return nil, err } - //Activate HA + // Activate HA if vmr.haState == "" { paramMap := map[string]interface{}{ "sid": vmr.vmId, @@ -1525,7 +1564,7 @@ func (c *Client) UpdateVMHA(vmr *VmRef, haState string, haGroup string) (exitSta } } - //Set wanted state + // Set wanted state paramMap := map[string]interface{}{ "state": haState, "group": haGroup, @@ -1573,8 +1612,7 @@ func (c *Client) DeletePool(poolid string) error { return c.Delete("/pools/" + poolid) } -//permissions check - +// permissions check func (c *Client) GetUserPermissions(id UserID, path string) (permissions []string, err error) { existence, err := CheckUserExistence(id, c) if err != nil { From 2447a8748faf749c52c7a609665723b1169c02e3 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Thu, 4 May 2023 12:05:12 +0100 Subject: [PATCH 143/191] Test Cloud-init At the moment it is very basic testing --- Vagrantfile | 6 +++ scripts/vagrant-get-cloudinit-template.sh | 3 ++ test/api/CloudInit/cloudinit_test.go | 55 +++++++++++++++++++ test/api/CloudInit/shared_test.go | 65 +++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 scripts/vagrant-get-cloudinit-template.sh create mode 100644 test/api/CloudInit/cloudinit_test.go create mode 100644 test/api/CloudInit/shared_test.go diff --git a/Vagrantfile b/Vagrantfile index 017f33f3..b27db063 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -22,6 +22,12 @@ Vagrant.configure("2") do |config| path: './scripts/vagrant-get-container-template.sh', run: "always" + config.vm.provision "Download Cloud-Init Template", + type: "shell", + privileged: true, + path: './scripts/vagrant-get-cloudinit-template.sh', + run: "always" + config.vm.provider :virtualbox do |vb| vb.memory = 2048 vb.cpus = 2 diff --git a/scripts/vagrant-get-cloudinit-template.sh b/scripts/vagrant-get-cloudinit-template.sh new file mode 100644 index 00000000..2e734d08 --- /dev/null +++ b/scripts/vagrant-get-cloudinit-template.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +wget -O /tmp/jammy-server-cloudimg-amd64.img https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img \ No newline at end of file diff --git a/test/api/CloudInit/cloudinit_test.go b/test/api/CloudInit/cloudinit_test.go new file mode 100644 index 00000000..68c5a275 --- /dev/null +++ b/test/api/CloudInit/cloudinit_test.go @@ -0,0 +1,55 @@ +package api_test + +import ( + "testing" + + pxapi "github.com/Telmate/proxmox-api-go/proxmox" + api_test "github.com/Telmate/proxmox-api-go/test/api" + "github.com/stretchr/testify/require" +) + +func Test_Cloud_Init_VM(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + config := _create_vm_spec(true) + vmref := _create_vmref() + + // Create network + configNetwork := _create_network_spec() + + err := configNetwork.CreateNetwork(Test.GetClient()) + require.NoError(t, err) + _, err = Test.GetClient().ApplyNetwork("pve") + require.NoError(t, err) + + disk := make(map[string]interface{}) + disk["import-from"] = "/tmp/jammy-server-cloudimg-amd64.img" + disk["type"] = "virtio" + disk["storage"] = "local" + + config.QemuDisks[0] = disk + config.Name = "Base-Image" + + err = config.CreateVm(vmref, Test.GetClient()) + require.NoError(t, err) + + config.Ipconfig = pxapi.IpconfigMap{} + config.Boot = "order=virtio0;ide2;net0" + + config.Ipconfig[0] = "gw=10.0.0.1,ip=10.0.0.2/24" + + err = config.UpdateConfig(vmref, Test.GetClient()) + require.NoError(t, err) + + testConfig, _ := pxapi.NewConfigQemuFromApi(vmref, Test.GetClient()) + + require.Equal(t, testConfig.Ipconfig[0], "gw=10.0.0.1,ip=10.0.0.2/24") + + _, err = Test.GetClient().DeleteVm(vmref) + require.NoError(t, err) + + _, err = Test.GetClient().DeleteNetwork("pve", "vmbr0") + require.NoError(t, err) + _, err = Test.GetClient().ApplyNetwork("pve") + require.NoError(t, err) +} diff --git a/test/api/CloudInit/shared_test.go b/test/api/CloudInit/shared_test.go new file mode 100644 index 00000000..abe34d8c --- /dev/null +++ b/test/api/CloudInit/shared_test.go @@ -0,0 +1,65 @@ +package api_test + +import ( + pxapi "github.com/Telmate/proxmox-api-go/proxmox" +) + +func _create_basevmref() (ref *pxapi.VmRef) { + ref = pxapi.NewVmRef(100) + ref.SetNode("pve") + ref.SetVmType("qemu") + return ref +} +func _create_vmref() (ref *pxapi.VmRef) { + ref = pxapi.NewVmRef(101) + ref.SetNode("pve") + ref.SetVmType("qemu") + return ref +} + +func _create_vm_spec(network bool) pxapi.ConfigQemu { + + disks := make(pxapi.QemuDevices) + + networks := make(pxapi.QemuDevices) + if network { + networks[0] = make(map[string]interface{}) + networks[0]["bridge"] = "vmbr0" + networks[0]["firewall"] = "true" + networks[0]["id"] = "0" + networks[0]["macaddr"] = "B6:8F:9D:7C:8F:BC" + networks[0]["model"] = "virtio" + } + + config := pxapi.ConfigQemu{ + Name: "test-qemu01", + Bios: "seabios", + Tablet: pxapi.PointerBool(true), + Memory: 2048, + QemuOs: "l26", + QemuCores: 1, + QemuSockets: 1, + QemuCpu: "kvm64", + QemuNuma: pxapi.PointerBool(false), + QemuKVM: pxapi.PointerBool(true), + Hotplug: "network,disk,usb", + QemuNetworks: networks, + QemuIso: "none", + Boot: "order=ide2;net0", + Scsihw: "virtio-scsi-pci", + QemuDisks: disks, + } + + return config +} + +func _create_network_spec() pxapi.ConfigNetwork { + config := pxapi.ConfigNetwork{ + Type: "bridge", + Iface: "vmbr0", + Node: "pve", + Autostart: true, + } + + return config +} From 517592649f5de5d65dbae462c8eef50371a3de14 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Fri, 5 May 2023 09:13:49 +0100 Subject: [PATCH 144/191] Removed unused function --- test/api/Test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/api/Test.go b/test/api/Test.go index d1171a5f..e09b7fcb 100644 --- a/test/api/Test.go +++ b/test/api/Test.go @@ -2,6 +2,7 @@ package api_test import ( "crypto/tls" + pxapi "github.com/Telmate/proxmox-api-go/proxmox" ) @@ -13,12 +14,12 @@ type Test struct { HttpHeaders string RequireSSL bool - _client *pxapi.Client + _client *pxapi.Client } func (test *Test) CreateClient() (err error) { if test.APIurl == "" { - test.APIurl = "https://127.0.0.1:8006/api2/json" + test.APIurl = "https://172.26.8.219:8006/api2/json" } if test.UserID == "" { test.UserID = "root@pam" @@ -40,7 +41,6 @@ func (test *Test) GetClient() (client *pxapi.Client) { return test._client } - func (test *Test) Login() (err error) { if test._client == nil { err = test.CreateClient() From c8054cdacc0925b8c4648b48ec82d5b8f50927e9 Mon Sep 17 00:00:00 2001 From: Richard Franks Date: Fri, 5 May 2023 09:31:07 +0100 Subject: [PATCH 145/191] . --- test/api/CloudInit/shared_test.go | 6 ------ test/api/Test.go | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/test/api/CloudInit/shared_test.go b/test/api/CloudInit/shared_test.go index abe34d8c..ecdebb3a 100644 --- a/test/api/CloudInit/shared_test.go +++ b/test/api/CloudInit/shared_test.go @@ -4,12 +4,6 @@ import ( pxapi "github.com/Telmate/proxmox-api-go/proxmox" ) -func _create_basevmref() (ref *pxapi.VmRef) { - ref = pxapi.NewVmRef(100) - ref.SetNode("pve") - ref.SetVmType("qemu") - return ref -} func _create_vmref() (ref *pxapi.VmRef) { ref = pxapi.NewVmRef(101) ref.SetNode("pve") diff --git a/test/api/Test.go b/test/api/Test.go index e09b7fcb..6a71fa8a 100644 --- a/test/api/Test.go +++ b/test/api/Test.go @@ -19,7 +19,7 @@ type Test struct { func (test *Test) CreateClient() (err error) { if test.APIurl == "" { - test.APIurl = "https://172.26.8.219:8006/api2/json" + test.APIurl = "https://127.0.0.1:8006/api2/json" } if test.UserID == "" { test.UserID = "root@pam" From 8c1c265f3f9cd5e4f00d9407ccb3b81e022090b6 Mon Sep 17 00:00:00 2001 From: Pascal Kutscha Date: Fri, 5 May 2023 21:00:16 +0200 Subject: [PATCH 146/191] added HaGroups retrieving --- proxmox/config_hagroup.go | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 proxmox/config_hagroup.go diff --git a/proxmox/config_hagroup.go b/proxmox/config_hagroup.go new file mode 100644 index 00000000..e9f9ad9a --- /dev/null +++ b/proxmox/config_hagroup.go @@ -0,0 +1,53 @@ +package proxmox + +import "strings" + +type HAGroup struct { + Comment string // Description. + Group string // The HA group identifier. + Nodes []string // List of cluster node names with optional priority. LIKE: [:]{,[:]}* + NoFailback bool // The CRM tries to run services on the node with the highest priority. If a node with higher priority comes online, the CRM migrates the service to that node. Enabling nofailback prevents that behavior. + Restricted bool // Resources bound to restricted groups may only run on nodes defined by the group. + Type string // Group type +} + +func (c *Client) GetHAGroupList() (haGroups []HAGroup, err error) { + list, err := c.GetItemList("/cluster/ha/groups") + + if err != nil { + return nil, err + } + + haGroups = []HAGroup{} + + for _, item := range list["data"].([]interface{}) { + itemMap := item.(map[string]interface{}) + + haGroups = append(haGroups, HAGroup{ + Comment: itemMap["comment"].(string), + Group: itemMap["group"].(string), + Nodes: strings.Split(itemMap["nodes"].(string), ","), + NoFailback: itemMap["nofailback"].(float64) == 1, + Restricted: itemMap["restricted"].(float64) == 1, + Type: itemMap["type"].(string), + }) + } + + return haGroups, nil +} + +func (c *Client) GetHAGroupByName(GroupName string) (*HAGroup, error) { + groups, err := c.GetHAGroupList() + + if err != nil { + return nil, err + } + + for _, item := range groups { + if item.Group == GroupName { + return &item, nil + } + } + + return nil, nil +} From 1b31f1aa63faadb731ca0cf39b0962de8aa06931 Mon Sep 17 00:00:00 2001 From: Pascal Kutscha Date: Fri, 5 May 2023 21:02:44 +0200 Subject: [PATCH 147/191] fixing error message when fetching HaGroupByName which does not exists! --- proxmox/config_hagroup.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proxmox/config_hagroup.go b/proxmox/config_hagroup.go index e9f9ad9a..67adfea1 100644 --- a/proxmox/config_hagroup.go +++ b/proxmox/config_hagroup.go @@ -1,6 +1,9 @@ package proxmox -import "strings" +import ( + "errors" + "strings" +) type HAGroup struct { Comment string // Description. @@ -49,5 +52,5 @@ func (c *Client) GetHAGroupByName(GroupName string) (*HAGroup, error) { } } - return nil, nil + return nil, errors.New("cannot find HaGroup by name " + GroupName) } From 90253b9aeb74487967fa48843add5fc33c0c17e1 Mon Sep 17 00:00:00 2001 From: Christian Benincasa Date: Thu, 11 May 2023 14:26:18 -0400 Subject: [PATCH 148/191] Fix POST /nodes/{node}/lxc/{id}/template --- proxmox/client.go | 4 +++- test/api/Lxc/lxc_create_update_delete_test.go | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index b1edab45..69da8053 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -380,7 +380,9 @@ func (c *Client) CreateTemplate(vmr *VmRef) error { return err } - if exitStatus != "OK" { + // Specifically ignore empty exit status for LXCs, since they don't return a task ID + // when creating templates in the first place (but still successfully create them). + if exitStatus != "OK" && vmr.vmType != "lxc" { return errors.New("Can't convert Vm to template:" + exitStatus) } diff --git a/test/api/Lxc/lxc_create_update_delete_test.go b/test/api/Lxc/lxc_create_update_delete_test.go index d3940ad4..ba0d9d52 100644 --- a/test/api/Lxc/lxc_create_update_delete_test.go +++ b/test/api/Lxc/lxc_create_update_delete_test.go @@ -54,3 +54,16 @@ func Test_Remove_Lxc_Container(t *testing.T) { require.NoError(t, err) } + +func Test_Create_Template_Lxc_Container(t *testing.T) { + Test := api_test.Test{} + _ = Test.CreateTest() + config := _create_lxc_spec(true) + + vmRef := _create_vmref() + err := config.CreateLxc(vmRef, Test.GetClient()) + require.NoError(t, err) + + err = Test.GetClient().CreateTemplate(vmRef) + require.NoError(t, err) +} From 68d4b6775a64a2197dd415671b34ee1d87982f93 Mon Sep 17 00:00:00 2001 From: mleone87 <807457+mleone87@users.noreply.github.com> Date: Sun, 14 May 2023 22:59:36 +0200 Subject: [PATCH 149/191] Remove unused TravisCI --- .travis.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3dc966bd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: go - -go: - - 1.16.x - -dist: focal - -cache: - directories: - - /home/travis/.vagrant.d/boxes - -env: - global: - - GO111MODULE=on - -install: - # install build dependencies for vagrant-libvirt - - sudo apt-get update && sudo apt-get build-dep vagrant ruby-libvirt && sudo apt-get install -y qemu libvirt-daemon-system libvirt-clients ebtables dnsmasq-base libxslt-dev libxml2-dev libvirt-dev zlib1g-dev ruby-dev qemu-utils qemu-kvm - - # install vagrant - - sudo wget -nv https://releases.hashicorp.com/vagrant/2.2.14/vagrant_2.2.14_x86_64.deb - - sudo dpkg -i vagrant_2.2.14_x86_64.deb - - # install vagrant-libvirt plugin - - sudo vagrant plugin install vagrant-libvirt - -script: - - sudo vagrant up --provider=libvirt - - make test From 4f314bf82c92c6a14a6cd34a037a29256611c394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Pecchia?= <179218+mabeett@users.noreply.github.com> Date: Mon, 22 May 2023 00:04:51 +0200 Subject: [PATCH 150/191] feat: support VM VirtIO-based Random Number Generator configuration --- README.md | 5 +++++ proxmox/config_qemu.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/README.md b/README.md index 002708fd..7093cdce 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,11 @@ createQemu JSON Sample: "tag": -1 } }, + "rng0": { + "source": "/dev/urandom", + "max_bytes": "1024", + "period": "1000" + }, "usb": { "0": { "host": "0658:0200", diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 2f3e8d5b..42156f52 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -48,6 +48,7 @@ type ConfigQemu struct { Description string `json:"description,omitempty"` Disks *QemuStorages `json:"disks,omitempty"` EFIDisk QemuDevice `json:"efidisk,omitempty"` // TODO should be a struct + RNGDrive QemuDevice `json:"rng0,omitempty"` // TODO should be a struct FullClone *int `json:"fullclone,omitempty"` // TODO should probably be a bool HaGroup string `json:"hagroup,omitempty"` HaState string `json:"hastate,omitempty"` // TODO should be custom type with enum @@ -179,6 +180,9 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) { // Create EFI disk config.CreateQemuEfiParams(params) + // Create VirtIO RNG + config.CreateQemuRngParams(params) + // Create vga config. vgaParam := QemuDeviceParam{} vgaParam = vgaParam.createDeviceParam(config.QemuVga, nil) @@ -226,6 +230,9 @@ func (config *ConfigQemu) defaults() { if config.Bios == "" { config.Bios = "seabios" } + if config.RNGDrive == nil { + config.RNGDrive = QemuDevice{} + } if config.EFIDisk == nil { config.EFIDisk = QemuDevice{} } @@ -419,6 +426,9 @@ func (config ConfigQemu) mapToApiValues(currentConfig ConfigQemu) (rebootRequire // Create EFI disk config.CreateQemuEfiParams(params) + // Create VirtIO RNG + config.CreateQemuRngParams(params) + // Create networks config. config.CreateQemuNetworksParams(params) @@ -1503,6 +1513,25 @@ func (c ConfigQemu) CreateIpconfigParams(params map[string]interface{}) error { return nil } +// Create RNG parameter. +func (c ConfigQemu) CreateQemuRngParams(params map[string]interface{}) { + rngParam := QemuDeviceParam{} + rngParam = rngParam.createDeviceParam(c.RNGDrive, nil) + + if len(rngParam) > 0 { + rng_info := []string{} + rng := "" + for _, param := range rngParam { + key := strings.Split(param, "=") + rng_info = append(rng_info, fmt.Sprintf("%s=%s", key[0], key[1])) + } + if len(rng_info) > 0 { + rng = strings.Join(rng_info, ",") + params["rng0"] = rng + } + } +} + // Create efi parameter. func (c ConfigQemu) CreateQemuEfiParams(params map[string]interface{}) { efiParam := QemuDeviceParam{} @@ -1614,6 +1643,8 @@ func (p QemuDeviceParam) createDeviceParam( confValue = sValue } else if iValue, ok := value.(int); ok && iValue > 0 { confValue = iValue + } else if iValue, ok := value.(float64); ok && iValue > 0 { + confValue = iValue } if confValue != nil { deviceConf := fmt.Sprintf("%v=%v", key, confValue) From efc4ce29c1b98e56ddf042d4f1382b87e2f800f3 Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 27 May 2023 09:38:08 +0300 Subject: [PATCH 151/191] Zones API is supported. Start of the DNS API. --- main.go | 84 +++++++++++++++++++ proxmox/client.go | 90 ++++++++++++++++++++ proxmox/config_sdn.go | 185 ++++++++++++++++++++++++++++++++++++++++++ proxmox/util.go | 9 ++ 4 files changed, 368 insertions(+) create mode 100644 proxmox/config_sdn.go diff --git a/main.go b/main.go index b790e855..d572b1d0 100644 --- a/main.go +++ b/main.go @@ -785,6 +785,90 @@ func main() { } log.Printf("Network configuration on node %s has been reverted\n", node) + //SDN + case "applySDN": + exitStatus, err := c.ApplySDN() + if err != nil { + failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus)) + } + log.Printf("SDN configuration has been applied\n") + + case "getZonesList": + zones, err := c.GetSDNZones(true, "") + if err != nil { + log.Printf("Error listing SDN zones %+v\n", err) + os.Exit(1) + } + zonesList, err := json.Marshal(zones) + failError(err) + fmt.Println(string(zonesList)) + + case "getZone": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: Zone name is needed")) + } + zoneName := flag.Args()[1] + zone, err := c.GetSDNZone(zoneName) + if err != nil { + log.Printf("Error listing SDN zones %+v\n", err) + os.Exit(1) + } + zoneList, err := json.Marshal(zone) + failError(err) + fmt.Println(string(zoneList)) + + case "createZone": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: Zone name is needed")) + } + zoneName := flag.Args()[1] + config, err := proxmox.NewConfigSDNZoneFromJson(GetConfig(*fConfigFile)) + failError(err) + failError(config.CreateWithValidate(zoneName, c)) + log.Printf("Zone %s has been created\n", zoneName) + + case "deleteZone": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: zone name required")) + } + zoneName := flag.Args()[1] + err := c.DeleteSDNZone(zoneName) + failError(err) + + case "updateZone": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: zone name required")) + } + zoneName := flag.Args()[1] + config, err := proxmox.NewConfigSDNZoneFromJson(GetConfig(*fConfigFile)) + failError(err) + failError(config.UpdateWithValidate(zoneName, c)) + log.Printf("Zone %s has been updated\n", zoneName) + + case "getDNSList": + dns, err := c.GetSDNDNSs("") + if err != nil { + log.Printf("Error listing SDN DNS entries %+v\n", err) + os.Exit(1) + } + dnsList, err := json.Marshal(dns) + failError(err) + fmt.Println(string(dnsList)) + + case "getDNS": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: DNS name is needed")) + } + name := flag.Args()[1] + dns, err := c.GetSDNDNS(name) + if err != nil { + log.Printf("Error listing SDN DNS %+v\n", err) + os.Exit(1) + } + dnsList, err := json.Marshal(dns) + failError(err) + fmt.Println(string(dnsList)) + default: fmt.Printf("unknown action, try start|stop vmid\n") } diff --git a/proxmox/client.go b/proxmox/client.go index d71dc144..48004e1e 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -30,6 +30,7 @@ type Client struct { ApiUrl string Username string Password string + ApiToken string Otp string TaskTimeout int } @@ -1837,6 +1838,95 @@ func (c *Client) RevertNetwork(node string) (exitStatus string, err error) { return c.DeleteWithTask(url) } +// SDN + +func (c *Client) ApplySDN() (string, error) { + return c.PutWithTask(nil, "/cluster/sdn") +} + +// GetSDNDNSs returns a list of all DNS definitions in the "data" element of the returned +// map. +func (c *Client) GetSDNDNSs(typeFilter string) (list map[string]interface{}, err error) { + url := "/cluster/sdn/dns" + if typeFilter != "" { + url += fmt.Sprintf("&type=%s", typeFilter) + } + err = c.GetJsonRetryable(url, &list, 3) + return +} + +// CheckSDNDNSExistance returns true if a DNS entry with the provided ID exists, false otherwise. +func (c *Client) CheckSDNDNSExistance(id string) (existance bool, err error) { + list, err := c.GetSDNDNSs("") + existance = ItemInKeyOfArray(list["data"].([]interface{}), "dns", id) + return +} + +// GetSDNDNS returns details about the DNS entry whose name was provided. +// An error is returned if the zone doesn't exist. +// The returned zone can be unmarshalled into a ConfigSDNDNS struct. +func (c *Client) GetSDNDNS(name string) (dns map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/dns/%s", name) + err = c.GetJsonRetryable(url, &dns, 3) + return +} + +// CreateSDNDNS creates a new SDN DNS in the cluster +func (c *Client) CreateSDNDNS(params map[string]interface{}) error { + return c.Post(params, "/cluster/sdn/dns") +} + +// DeleteSDNDNS deletes an existing SDN DNS in the cluster +func (c *Client) DeleteSDNDNS(name string) error { + return c.Delete(fmt.Sprintf("/cluster/sdn/dns/%s", name)) +} + +// UpdateSDNDNS updates the given DNS with the provided parameters +func (c *Client) UpdateSDNDNS(id string, params map[string]interface{}) error { + return c.Put(params, "/cluster/sdn/dns/"+id) +} + +// GetSDNZones returns a list of all the SDN zones defined in the cluster. +func (c *Client) GetSDNZones(pending bool, typeFilter string) (list map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/zones?pending=%d", Btoi(pending)) + if typeFilter != "" { + url += fmt.Sprintf("&type=%s", typeFilter) + } + err = c.GetJsonRetryable(url, &list, 3) + return +} + +// CheckSDNZoneExistance returns true if a zone with the provided ID exists, false otherwise. +func (c *Client) CheckSDNZoneExistance(id string) (existance bool, err error) { + list, err := c.GetSDNZones(true, "") + existance = ItemInKeyOfArray(list["data"].([]interface{}), "zone", id) + return +} + +// GetSDNZone returns details about the zone whose name was provided. +// An error is returned if the zone doesn't exist. +// The returned zone can be unmarshalled into a ConfigSDNZone struct. +func (c *Client) GetSDNZone(zoneName string) (zone map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/zones/%s", zoneName) + err = c.GetJsonRetryable(url, &zone, 3) + return +} + +// CreateSDNZone creates a new SDN zone in the cluster +func (c *Client) CreateSDNZone(params map[string]interface{}) error { + return c.Post(params, "/cluster/sdn/zones") +} + +// DeleteSDNZone deletes an existing SDN zone in the cluster +func (c *Client) DeleteSDNZone(zoneName string) error { + return c.Delete(fmt.Sprintf("/cluster/sdn/zones/%s", zoneName)) +} + +// UpdateSDNZone updates the given zone with the provided parameters +func (c *Client) UpdateSDNZone(id string, params map[string]interface{}) error { + return c.Put(params, "/cluster/sdn/zones/"+id) +} + // Shared func (c *Client) GetItemConfigMapStringInterface(url, text, message string) (map[string]interface{}, error) { data, err := c.GetItemConfig(url, text, message) diff --git a/proxmox/config_sdn.go b/proxmox/config_sdn.go new file mode 100644 index 00000000..ea0a4568 --- /dev/null +++ b/proxmox/config_sdn.go @@ -0,0 +1,185 @@ +package proxmox + +import ( + "encoding/json" + "fmt" +) + +// ConfigSDNDNS describes the SDN DNS configurable element +type ConfigSDNDNS struct { + DNS string `json:"dns"` + Key string `json:"key"` + Type string `json:"type"` + URL string `json:"url"` + TTL int `json:"ttl,omitempty"` + // The SDN Plugin schema contains ReverseV6Mask attribute while the + // PowerDNS plugin schema contains the ReverseMaskV6 attribute + // This is probably a bug that crept into the Proxmox implementation.a + // Checked in libpve-network-perl=0.7.3 + ReverseMaskV6 int `json:"reversemaskv6,omitempty"` + ReverseV6Mask int `json:"reversev6mask,omitempty"` + // Digest allows for a form of optimistic locking + Digest string `json:"digest,omitempty"` +} + +func NewConfigSDNDNSFromJson(input []byte) (config *ConfigSDNDNS, err error) { + config = &ConfigSDNDNS{} + err = json.Unmarshal([]byte(input), config) + return +} + +// ConfigSDNZone describes the Zone configurable element +type ConfigSDNZone struct { + Type string `json:"type"` + Zone string `json:"zone"` + AdvertiseSubnets bool `json:"advertise-subnets,omitempty"` + Bridge string `json:"bridge,omitempty"` + BridgeDisableMacLearning bool `json:"bridge-disable-mac-learning,omitempty"` + Controller string `json:"controller,omitempty"` + Delete string `json:"delete,omitempty"` + DisableARPNDSuppression bool `json:"disable-arp-nd-suppression,omitempty"` + DNS string `json:"dns,omitempty"` + DNSZone string `json:"dnszone,omitempty"` + DPID int `json:"dp-id,omitempty"` + ExitNodes string `json:"exitnodes,omitempty"` + ExitNodesLocalRouting bool `json:"exitnodes-local-routing,omitempty"` + ExitNodesPrimary string `json:"exitnodes-primary,omitempty"` + IPAM string `json:"ipam,omitempty"` + MAC string `json:"mac,omitempty"` + MTU int `json:"mtu,omitempty"` + Nodes string `json:"nodes,omitempty"` + Peers string `json:"peers,omitempty"` + ReverseDNS string `json:"reversedns,omitempty"` + RTImport string `json:"rt-import,omitempty"` + Tag int `json:"tag,omitempty"` + VlanProtocol string `json:"vlan-protocol,omitempty"` + VrfVxlan int `json:"vrf-vxlan,omitempty"` + // Digest allows for a form of optimistic locking + Digest string `json:"digest,omitempty"` +} + +// NewConfigNetworkFromJSON takes in a byte array from a json encoded SDN Zone +// configuration and stores it in config. +// It returns the newly created config with the passed in configuration stored +// and an error if one occurs unmarshalling the input data. +func NewConfigSDNZoneFromJson(input []byte) (config *ConfigSDNZone, err error) { + config = &ConfigSDNZone{} + err = json.Unmarshal([]byte(input), config) + return +} + +func (config *ConfigSDNZone) CreateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, true, client) + if err != nil { + return + } + return config.Create(id, client) +} + +func (config *ConfigSDNZone) Create(id string, client *Client) (err error) { + config.Zone = id + params := config.mapToApiValues() + return client.CreateSDNZone(params) +} + +func (config *ConfigSDNZone) UpdateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, false, client) + if err != nil { + return + } + return config.Update(id, client) +} + +func (config *ConfigSDNZone) Update(id string, client *Client) (err error) { + config.Zone = id + params := config.mapToApiValues() + err = client.UpdateSDNZone(id, params) + if err != nil { + params, _ := json.Marshal(¶ms) + return fmt.Errorf("error updating SDN Zone: %v, (params: %v)", err, string(params)) + } + return +} + +func (c *ConfigSDNZone) Validate(id string, create bool, client *Client) (err error) { + exists, err := client.CheckSDNZoneExistance(id) + if err != nil { + return + } + if exists && create { + return ErrorItemExists(id, "zone") + } + if !exists && !create { + return ErrorItemNotExists(id, "zone") + } + + err = ValidateStringInArray([]string{"evpn", "qinq", "simple", "vlan", "vxlan"}, c.Type, "type") + if err != nil { + return + } + switch c.Type { + case "simple": + case "vlan": + if create { + if c.Bridge == "" { + return ErrorKeyEmpty("bridge") + } + } + case "qinq": + if create { + if c.Bridge == "" { + return ErrorKeyEmpty("bridge") + } + if c.Tag <= 0 { + return ErrorKeyEmpty("tag") + } + if c.VlanProtocol == "" { + return ErrorKeyEmpty("vlan-protocol") + } + } + case "vxlan": + if create { + if c.Peers == "" { + return ErrorKeyEmpty("peers") + } + } + case "evpn": + if create { + if c.VrfVxlan < 0 { + return ErrorKeyEmpty("vrf-vxlan") + } + if c.Controller == "" { + return ErrorKeyEmpty("controller") + } + } + } + if c.VlanProtocol != "" { + err = ValidateStringInArray([]string{"802.1q", "802.1ad"}, c.VlanProtocol, "vlan-protocol") + if err != nil { + return + } + } + return +} + +func (config *ConfigSDNZone) mapToApiValues() (params map[string]interface{}) { + + d, _ := json.Marshal(config) + json.Unmarshal(d, ¶ms) + + boolsToFix := []string{ + "advertise-subnets", + "bridge-disable-mac-learning", + "disable-arp-nd-suppression", + "exitnodes-local-routing", + } + for _, key := range boolsToFix { + if v, has := params[key]; has { + params[key] = Btoi(v.(bool)) + } + } + // Remove the zone and type (path parameters) from the map + delete(params, "zone") + delete(params, "type") + return +} diff --git a/proxmox/util.go b/proxmox/util.go index 400f91e6..34eec5fe 100644 --- a/proxmox/util.go +++ b/proxmox/util.go @@ -19,6 +19,15 @@ func inArray(arr []string, str string) bool { return false } +func Btoi(b bool) int { + switch b { + case true: + return 1 + default: + return 0 + } +} + func Itob(i int) bool { return i == 1 } From 10081777d6cc5d5142d3bdd7765990da327235ce Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 27 May 2023 17:41:00 +0300 Subject: [PATCH 152/191] Added support for vnets and subnets --- main.go | 52 +++++++++++++ proxmox/client.go | 78 ++++++++++++++++++++ proxmox/config_sdn.go | 23 ------ proxmox/config_sdn_dns.go | 91 +++++++++++++++++++++++ proxmox/config_sdn_subnet.go | 139 +++++++++++++++++++++++++++++++++++ proxmox/config_sdn_vnet.go | 100 +++++++++++++++++++++++++ 6 files changed, 460 insertions(+), 23 deletions(-) create mode 100644 proxmox/config_sdn_dns.go create mode 100644 proxmox/config_sdn_subnet.go create mode 100644 proxmox/config_sdn_vnet.go diff --git a/main.go b/main.go index d572b1d0..1c0dd2a4 100644 --- a/main.go +++ b/main.go @@ -845,6 +845,58 @@ func main() { failError(config.UpdateWithValidate(zoneName, c)) log.Printf("Zone %s has been updated\n", zoneName) + case "getVNetsList": + zones, err := c.GetSDNVNets(true) + if err != nil { + log.Printf("Error listing SDN zones %+v\n", err) + os.Exit(1) + } + vnetsList, err := json.Marshal(zones) + failError(err) + fmt.Println(string(vnetsList)) + + case "getVNet": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: VNet name is needed")) + } + vnetName := flag.Args()[1] + vnet, err := c.GetSDNVNet(vnetName) + if err != nil { + log.Printf("Error listing SDN VNets %+v\n", err) + os.Exit(1) + } + vnetsList, err := json.Marshal(vnet) + failError(err) + fmt.Println(string(vnetsList)) + + case "createVNet": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: VNet name is needed")) + } + vnetName := flag.Args()[1] + config, err := proxmox.NewConfigSDNVNetFromJson(GetConfig(*fConfigFile)) + failError(err) + failError(config.CreateWithValidate(vnetName, c)) + log.Printf("VNet %s has been created\n", vnetName) + + case "deleteVNet": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: VNet name required")) + } + vnetName := flag.Args()[1] + err := c.DeleteSDNVNet(vnetName) + failError(err) + + case "updateVNet": + if len(flag.Args()) < 2 { + failError(fmt.Errorf("error: zone name required")) + } + vnetName := flag.Args()[1] + config, err := proxmox.NewConfigSDNVNetFromJson(GetConfig(*fConfigFile)) + failError(err) + failError(config.UpdateWithValidate(vnetName, c)) + log.Printf("VNet %s has been updated\n", vnetName) + case "getDNSList": dns, err := c.GetSDNDNSs("") if err != nil { diff --git a/proxmox/client.go b/proxmox/client.go index 48004e1e..3be0efd9 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -1844,6 +1844,84 @@ func (c *Client) ApplySDN() (string, error) { return c.PutWithTask(nil, "/cluster/sdn") } +// GetSDNVNets returns a list of all VNet definitions in the "data" element of the returned +// map. +func (c *Client) GetSDNVNets(pending bool) (list map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/vnets?pending=%d", Btoi(pending)) + err = c.GetJsonRetryable(url, &list, 3) + return +} + +// CheckSDNVNetExistance returns true if a DNS entry with the provided ID exists, false otherwise. +func (c *Client) CheckSDNVNetExistance(id string) (existance bool, err error) { + list, err := c.GetSDNVNets(true) + existance = ItemInKeyOfArray(list["data"].([]interface{}), "vnet", id) + return +} + +// GetSDNVNet returns details about the DNS entry whose name was provided. +// An error is returned if the zone doesn't exist. +// The returned zone can be unmarshalled into a ConfigSDNVNet struct. +func (c *Client) GetSDNVNet(name string) (dns map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/vnets/%s", name) + err = c.GetJsonRetryable(url, &dns, 3) + return +} + +// CreateSDNVNet creates a new SDN DNS in the cluster +func (c *Client) CreateSDNVNet(params map[string]interface{}) error { + return c.Post(params, "/cluster/sdn/vnets") +} + +// DeleteSDNVNet deletes an existing SDN DNS in the cluster +func (c *Client) DeleteSDNVNet(name string) error { + return c.Delete(fmt.Sprintf("/cluster/sdn/vnets/%s", name)) +} + +// UpdateSDNVNet updates the given DNS with the provided parameters +func (c *Client) UpdateSDNVNet(id string, params map[string]interface{}) error { + return c.Put(params, "/cluster/sdn/vnets/"+id) +} + +// GetSDNSubnets returns a list of all Subnet definitions in the "data" element of the returned +// map. +func (c *Client) GetSDNSubnets(vnet string) (list map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/vnets/%s/subnets", vnet) + err = c.GetJsonRetryable(url, &list, 3) + return +} + +// CheckSDNSubnetExistance returns true if a DNS entry with the provided ID exists, false otherwise. +func (c *Client) CheckSDNSubnetExistance(vnet, id string) (existance bool, err error) { + list, err := c.GetSDNSubnets(vnet) + existance = ItemInKeyOfArray(list["data"].([]interface{}), "subnet", id) + return +} + +// GetSDNSubnet returns details about the Subnet entry whose name was provided. +// An error is returned if the zone doesn't exist. +// The returned map["data"] section can be unmarshalled into a ConfigSDNSubnet struct. +func (c *Client) GetSDNSubnet(vnet, name string) (subnet map[string]interface{}, err error) { + url := fmt.Sprintf("/cluster/sdn/vnets/%s/subnets/%s", vnet, name) + err = c.GetJsonRetryable(url, &subnet, 3) + return +} + +// CreateSDNSubnet creates a new SDN DNS in the cluster +func (c *Client) CreateSDNSubnet(vnet string, params map[string]interface{}) error { + return c.Post(params, fmt.Sprintf("/cluster/sdn/vnets/%s/subnets", vnet)) +} + +// DeleteSDNSubnet deletes an existing SDN DNS in the cluster +func (c *Client) DeleteSDNSubnet(vnet, name string) error { + return c.Delete(fmt.Sprintf("/cluster/sdn/vnets/%s/subnets/%s", vnet, name)) +} + +// UpdateSDNSubnet updates the given DNS with the provided parameters +func (c *Client) UpdateSDNSubnet(vnet, id string, params map[string]interface{}) error { + return c.Put(params, fmt.Sprintf("/cluster/sdn/vnets/%s/subnets/%s", vnet, id)) +} + // GetSDNDNSs returns a list of all DNS definitions in the "data" element of the returned // map. func (c *Client) GetSDNDNSs(typeFilter string) (list map[string]interface{}, err error) { diff --git a/proxmox/config_sdn.go b/proxmox/config_sdn.go index ea0a4568..a20933e3 100644 --- a/proxmox/config_sdn.go +++ b/proxmox/config_sdn.go @@ -5,29 +5,6 @@ import ( "fmt" ) -// ConfigSDNDNS describes the SDN DNS configurable element -type ConfigSDNDNS struct { - DNS string `json:"dns"` - Key string `json:"key"` - Type string `json:"type"` - URL string `json:"url"` - TTL int `json:"ttl,omitempty"` - // The SDN Plugin schema contains ReverseV6Mask attribute while the - // PowerDNS plugin schema contains the ReverseMaskV6 attribute - // This is probably a bug that crept into the Proxmox implementation.a - // Checked in libpve-network-perl=0.7.3 - ReverseMaskV6 int `json:"reversemaskv6,omitempty"` - ReverseV6Mask int `json:"reversev6mask,omitempty"` - // Digest allows for a form of optimistic locking - Digest string `json:"digest,omitempty"` -} - -func NewConfigSDNDNSFromJson(input []byte) (config *ConfigSDNDNS, err error) { - config = &ConfigSDNDNS{} - err = json.Unmarshal([]byte(input), config) - return -} - // ConfigSDNZone describes the Zone configurable element type ConfigSDNZone struct { Type string `json:"type"` diff --git a/proxmox/config_sdn_dns.go b/proxmox/config_sdn_dns.go new file mode 100644 index 00000000..de97d188 --- /dev/null +++ b/proxmox/config_sdn_dns.go @@ -0,0 +1,91 @@ +package proxmox + +import ( + "encoding/json" + "fmt" +) + +// ConfigSDNDNS describes the SDN DNS configurable element +type ConfigSDNDNS struct { + DNS string `json:"dns"` + Key string `json:"key"` + Type string `json:"type"` + URL string `json:"url"` + TTL int `json:"ttl,omitempty"` + // The SDN Plugin schema contains ReverseV6Mask attribute while the + // PowerDNS plugin schema contains the ReverseMaskV6 attribute + // This is probably a bug that crept into the Proxmox implementation.a + // Checked in libpve-network-perl=0.7.3 + ReverseMaskV6 int `json:"reversemaskv6,omitempty"` + ReverseV6Mask int `json:"reversev6mask,omitempty"` + // Digest allows for a form of optimistic locking + Digest string `json:"digest,omitempty"` +} + +func NewConfigSDNDNSFromJson(input []byte) (config *ConfigSDNDNS, err error) { + config = &ConfigSDNDNS{} + err = json.Unmarshal([]byte(input), config) + return +} + +func (config *ConfigSDNDNS) CreateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, true, client) + if err != nil { + return + } + return config.Create(id, client) +} + +func (config *ConfigSDNDNS) Create(id string, client *Client) (err error) { + config.DNS = id + params := config.mapToApiValues() + return client.CreateSDNDNS(params) +} + +func (config *ConfigSDNDNS) UpdateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, false, client) + if err != nil { + return + } + return config.Update(id, client) +} + +func (config *ConfigSDNDNS) Update(id string, client *Client) (err error) { + config.DNS = id + params := config.mapToApiValues() + err = client.UpdateSDNDNS(id, params) + if err != nil { + params, _ := json.Marshal(¶ms) + return fmt.Errorf("error updating SDN DNS: %v, (params: %v)", err, string(params)) + } + return +} + +func (c *ConfigSDNDNS) Validate(id string, create bool, client *Client) (err error) { + exists, err := client.CheckSDNDNSExistance(id) + if err != nil { + return + } + if exists && create { + return ErrorItemExists(id, "dns") + } + if !exists && !create { + return ErrorItemNotExists(id, "dns") + } + + err = ValidateStringInArray([]string{"powerdns"}, c.Type, "type") + if err != nil { + return + } + err = ValidateIntGreater(0, c.TTL, "ttl") + if err != nil { + return + } + return +} + +func (config *ConfigSDNDNS) mapToApiValues() (params map[string]interface{}) { + d, _ := json.Marshal(config) + json.Unmarshal(d, ¶ms) + return +} diff --git a/proxmox/config_sdn_subnet.go b/proxmox/config_sdn_subnet.go new file mode 100644 index 00000000..195a3648 --- /dev/null +++ b/proxmox/config_sdn_subnet.go @@ -0,0 +1,139 @@ +package proxmox + +import ( + "encoding/json" + "fmt" + "net" +) + +/* + { + "cidr":"192.168.11.0/24", + "zone":"testlab", + "mask":"24", + "network":"192.168.11.0", + "type":"subnet", + "pending":{"gateway":"192.168.11.2"}, + "digest":null, + "snat":1, + "state":"changed", + "subnet":"testlab-192.168.11.0-24", + "vnet":"testlab1", + "gateway":"192.168.11.1" + } +*/ +type ConfigSDNSubnet struct { + // For creation purposes - Subnet is a CIDR + // Once a subnet has been created, the Subnet is an identifier with the format + // "--" + Subnet string `json:"subnet"` + + DNSZonePrefix string `json:"dnszoneprefix,omitempty"` + Gateway string `json:"gateway,omitempty"` + SNAT bool `json:"snat,omitempty"` + + // Delete is a string of attributes to be deleted from the object + Delete string `json:"delete,omitempty"` + // Type must always hold the string "subnet" + Type string `json:"type"` + // Digest allows for a form of optimistic locking + Digest string `json:"digest,omitempty"` +} + +// NewConfigSDNSubnetFromJSON takes in a byte array from a json encoded SDN Subnet +// configuration and stores it in config. +// It returns the newly created config with the passed in configuration stored +// and an error if one occurs unmarshalling the input data. +func NewConfigSDNSubnetFromJson(input []byte) (config *ConfigSDNSubnet, err error) { + config = &ConfigSDNSubnet{} + err = json.Unmarshal([]byte(input), config) + return +} + +func (config *ConfigSDNSubnet) CreateWithValidate(vnet, id string, client *Client) (err error) { + err = config.Validate(vnet, id, true, client) + if err != nil { + return + } + return config.Create(vnet, id, client) +} + +func (config *ConfigSDNSubnet) Create(vnet, id string, client *Client) (err error) { + config.Subnet = id + config.Type = "subnet" + params := config.mapToApiValues() + return client.CreateSDNSubnet(vnet, params) +} + +func (config *ConfigSDNSubnet) UpdateWithValidate(vnet, id string, client *Client) (err error) { + err = config.Validate(vnet, id, false, client) + if err != nil { + return + } + return config.Update(vnet, id, client) +} + +func (config *ConfigSDNSubnet) Update(vnet, id string, client *Client) (err error) { + config.Subnet = id + config.Type = "" // For some reason, this shouldn't be sent on update. Only on create. + params := config.mapToApiValues() + err = client.UpdateSDNSubnet(vnet, id, params) + if err != nil { + params, _ := json.Marshal(¶ms) + return fmt.Errorf("error updating SDN Subnet: %v, (params: %v)", err, string(params)) + } + return +} + +func (c *ConfigSDNSubnet) Validate(vnet, id string, create bool, client *Client) (err error) { + vnetExists, err := client.CheckSDNVNetExistance(vnet) + if err != nil { + return + } + if !vnetExists { + return fmt.Errorf("Subnet must be created in an existing vnet. Vnet (%s) wasn't found", vnet) + } + exists, err := client.CheckSDNSubnetExistance(vnet, id) + if err != nil { + return + } + if exists && create { + return ErrorItemExists(id, "subnet") + } + if !exists && !create { + return ErrorItemNotExists(id, "subnet") + } + + // if this is an update, the Subnet is an identifier of the form -- + // and therefore shouldn't be validated or changed + if create { + // Make sure that the CIDR is actually a valid CIDR + _, _, err = net.ParseCIDR(c.Subnet) + if err != nil { + return + } + } + + if c.Gateway != "" { + ip := net.ParseIP(c.Gateway) + if ip == nil { + return fmt.Errorf("error gateway (%s) is not a valid IP", c.Gateway) + } + } + + return +} + +func (config *ConfigSDNSubnet) mapToApiValues() (params map[string]interface{}) { + + d, _ := json.Marshal(config) + json.Unmarshal(d, ¶ms) + + if v, has := params["snat"]; has { + params["snat"] = Btoi(v.(bool)) + } + // Remove the subnet and vnet (path parameters) from the map + delete(params, "subnet") + delete(params, "vnet") + return +} diff --git a/proxmox/config_sdn_vnet.go b/proxmox/config_sdn_vnet.go new file mode 100644 index 00000000..7c6bf72c --- /dev/null +++ b/proxmox/config_sdn_vnet.go @@ -0,0 +1,100 @@ +package proxmox + +import ( + "encoding/json" + "fmt" + "regexp" +) + +type ConfigSDNVNet struct { + VNet string `json:"vnet"` + Zone string `json:"zone"` + Alias string `json:"alias,omitempty"` + Delete string `json:"delete,omitempty"` + Tag int `json:"tag,omitempty"` + VLANAware bool `json:"vlanaware,omitempty"` + // Digest allows for a form of optimistic locking + Digest string `json:"digest,omitempty"` +} + +func NewConfigSDNVNetFromJson(input []byte) (config *ConfigSDNVNet, err error) { + config = &ConfigSDNVNet{} + err = json.Unmarshal([]byte(input), config) + return +} + +func (config *ConfigSDNVNet) CreateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, true, client) + if err != nil { + return + } + return config.Create(id, client) +} + +func (config *ConfigSDNVNet) Create(id string, client *Client) (err error) { + config.VNet = id + params := config.mapToApiValues() + return client.CreateSDNVNet(params) +} + +func (config *ConfigSDNVNet) UpdateWithValidate(id string, client *Client) (err error) { + err = config.Validate(id, false, client) + if err != nil { + return + } + return config.Update(id, client) +} + +func (config *ConfigSDNVNet) Update(id string, client *Client) (err error) { + config.VNet = id + params := config.mapToApiValues() + err = client.UpdateSDNVNet(id, params) + if err != nil { + params, _ := json.Marshal(¶ms) + return fmt.Errorf("error updating SDN VNet: %v, (params: %v)", err, string(params)) + } + return +} + +func (c *ConfigSDNVNet) Validate(id string, create bool, client *Client) (err error) { + exists, err := client.CheckSDNVNetExistance(id) + if err != nil { + return + } + if exists && create { + return ErrorItemExists(id, "vnet") + } + if !exists && !create { + return ErrorItemNotExists(id, "vnet") + } + zoneExists, err := client.CheckSDNZoneExistance(c.Zone) + if err != nil { + return + } + if !zoneExists { + return fmt.Errorf("VNet must be associated to an existing zone. Zone %s could not be found.", c.Zone) + } + if c.Alias != "" { + regex, _ := regexp.Compile(`^(?^i:[\(\)-_.\w\d\s]{0,256})$`) + if !regex.Match([]byte(c.Alias)) { + return fmt.Errorf(`Alias must match the validation regular expression: ^(?^i:[\(\)-_.\w\d\s]{0,256})$`) + } + } + err = ValidateIntGreater(0, c.Tag, "tag") + if err != nil { + return + } + + return +} + +func (config *ConfigSDNVNet) mapToApiValues() (params map[string]interface{}) { + d, _ := json.Marshal(config) + json.Unmarshal(d, ¶ms) + + if v, has := params["vlanaware"]; has { + params["vlanaware"] = Btoi(v.(bool)) + } + + return +} From 27b12a7c996e73e0721bbc88179383d5a4a7e543 Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 27 May 2023 17:41:33 +0300 Subject: [PATCH 153/191] Renamed the zone source file for consistency --- proxmox/{config_sdn.go => config_sdn_zone.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename proxmox/{config_sdn.go => config_sdn_zone.go} (100%) diff --git a/proxmox/config_sdn.go b/proxmox/config_sdn_zone.go similarity index 100% rename from proxmox/config_sdn.go rename to proxmox/config_sdn_zone.go From 42cfca805f955de28ff4569fe0fcdbc28716dc73 Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 27 May 2023 18:12:35 +0300 Subject: [PATCH 154/191] commenting the delete field --- proxmox/config_sdn_zone.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxmox/config_sdn_zone.go b/proxmox/config_sdn_zone.go index a20933e3..6dd9dc3e 100644 --- a/proxmox/config_sdn_zone.go +++ b/proxmox/config_sdn_zone.go @@ -13,7 +13,6 @@ type ConfigSDNZone struct { Bridge string `json:"bridge,omitempty"` BridgeDisableMacLearning bool `json:"bridge-disable-mac-learning,omitempty"` Controller string `json:"controller,omitempty"` - Delete string `json:"delete,omitempty"` DisableARPNDSuppression bool `json:"disable-arp-nd-suppression,omitempty"` DNS string `json:"dns,omitempty"` DNSZone string `json:"dnszone,omitempty"` @@ -31,6 +30,8 @@ type ConfigSDNZone struct { Tag int `json:"tag,omitempty"` VlanProtocol string `json:"vlan-protocol,omitempty"` VrfVxlan int `json:"vrf-vxlan,omitempty"` + // Pass a string of attributes to be deleted from the remote object + Delete string `json:"delete,omitempty"` // Digest allows for a form of optimistic locking Digest string `json:"digest,omitempty"` } From 07699263d5528feac5579e988f5c4c504e315227 Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 27 May 2023 18:14:31 +0300 Subject: [PATCH 155/191] removed debug comment --- proxmox/config_sdn_subnet.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/proxmox/config_sdn_subnet.go b/proxmox/config_sdn_subnet.go index 195a3648..63bcd9bf 100644 --- a/proxmox/config_sdn_subnet.go +++ b/proxmox/config_sdn_subnet.go @@ -6,22 +6,6 @@ import ( "net" ) -/* - { - "cidr":"192.168.11.0/24", - "zone":"testlab", - "mask":"24", - "network":"192.168.11.0", - "type":"subnet", - "pending":{"gateway":"192.168.11.2"}, - "digest":null, - "snat":1, - "state":"changed", - "subnet":"testlab-192.168.11.0-24", - "vnet":"testlab1", - "gateway":"192.168.11.1" - } -*/ type ConfigSDNSubnet struct { // For creation purposes - Subnet is a CIDR // Once a subnet has been created, the Subnet is an identifier with the format From 73d24734757f9e20e9b757242f9c222fd17ff4a4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 4 Jun 2023 22:16:36 +0000 Subject: [PATCH 156/191] refactor: snapshot formatting Introduced the `rawSnapshots` type to help the user figure out how to transform it into a usable list or tree. --- cli/command/list/list-snapshots.go | 6 +++--- proxmox/snapshot.go | 18 ++++++++++-------- proxmox/snapshot_test.go | 8 ++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/cli/command/list/list-snapshots.go b/cli/command/list/list-snapshots.go index ea35b896..b7058105 100644 --- a/cli/command/list/list-snapshots.go +++ b/cli/command/list/list-snapshots.go @@ -16,7 +16,7 @@ var ( Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { id := cli.ValidateExistingGuestID(args, 0) - jBody, err := proxmox.ListSnapshots(cli.NewClient(), proxmox.NewVmRef(id)) + rawSnapshots, err := proxmox.ListSnapshots(cli.NewClient(), proxmox.NewVmRef(id)) if err != nil { noTree = false return @@ -24,9 +24,9 @@ var ( var list []*proxmox.Snapshot if noTree { noTree = false - list = proxmox.FormatSnapshotsList(jBody) + list = rawSnapshots.FormatSnapshotsList() } else { - list = proxmox.FormatSnapshotsTree(jBody) + list = rawSnapshots.FormatSnapshotsTree() } if len(list) == 0 { listCmd.Printf("Guest with ID (%d) has no snapshots", id) diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index 5ea77bf5..e58a43e9 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -35,10 +35,12 @@ func (config *ConfigSnapshot) CreateSnapshot(c *Client, guestId uint) (err error return } -func ListSnapshots(c *Client, vmr *VmRef) (taskResponse []interface{}, err error) { - err = c.CheckVmRef(vmr) +type rawSnapshots []interface{} + +func ListSnapshots(c *Client, vmr *VmRef) (rawSnapshots, error) { + err := c.CheckVmRef(vmr) if err != nil { - return + return nil, err } return c.GetItemConfigInterfaceArray("/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/snapshot/", "Guest", "SNAPSHOTS") } @@ -79,9 +81,9 @@ type Snapshot struct { } // Formats the taskResponse as a list of snapshots -func FormatSnapshotsList(taskResponse []interface{}) (list []*Snapshot) { - list = make([]*Snapshot, len(taskResponse)) - for i, e := range taskResponse { +func (raw rawSnapshots) FormatSnapshotsList() (list []*Snapshot) { + list = make([]*Snapshot, len(raw)) + for i, e := range raw { list[i] = &Snapshot{} if _, isSet := e.(map[string]interface{})["description"]; isSet { list[i].Description = e.(map[string]interface{})["description"].(string) @@ -103,8 +105,8 @@ func FormatSnapshotsList(taskResponse []interface{}) (list []*Snapshot) { } // Formats a list of snapshots as a tree of snapshots -func FormatSnapshotsTree(taskResponse []interface{}) (tree []*Snapshot) { - list := FormatSnapshotsList(taskResponse) +func (raw rawSnapshots) FormatSnapshotsTree() (tree []*Snapshot) { + list := raw.FormatSnapshotsList() for _, e := range list { for _, ee := range list { if e.Parent == ee.Name { diff --git a/proxmox/snapshot_test.go b/proxmox/snapshot_test.go index 2dce5a3e..cd640218 100644 --- a/proxmox/snapshot_test.go +++ b/proxmox/snapshot_test.go @@ -12,7 +12,7 @@ func Test_FormatSnapshotsTree(t *testing.T) { input := test_FormatSnapshots_Input() output := test_FormatSnapshotsTree_Output() for i, e := range input { - result, _ := json.Marshal(FormatSnapshotsTree(e)) + result, _ := json.Marshal(e.FormatSnapshotsTree()) require.JSONEq(t, output[i], string(result)) } } @@ -22,13 +22,13 @@ func Test_FormatSnapshotsList(t *testing.T) { input := test_FormatSnapshots_Input() output := test_FormatSnapshotsList_Output() for i, e := range input { - result, _ := json.Marshal(FormatSnapshotsList(e)) + result, _ := json.Marshal(e.FormatSnapshotsList()) require.JSONEq(t, output[i], string(result)) } } -func test_FormatSnapshots_Input() [][]interface{} { - return [][]interface{}{{map[string]interface{}{ +func test_FormatSnapshots_Input() []rawSnapshots { + return []rawSnapshots{{map[string]interface{}{ "name": "aa", "snaptime": float64(1666361849), "description": "", From 04bce30c93e0fb628697a0b9cbda88f77fee56c1 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 6 Jun 2023 17:52:07 +0000 Subject: [PATCH 157/191] refactor: better code reuse --- proxmox/client.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index d71dc144..71957574 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -159,18 +159,18 @@ func (c *Client) GetNodeList() (list map[string]interface{}, err error) { // GetResourceList returns a list of all enabled proxmox resources. // For resource types that can be in a disabled state, disabled resources // will not be returned -func (c *Client) GetResourceList(resourceType string) (list map[string]interface{}, err error) { - endpoint := "/cluster/resources" +// TODO this func should not be exported +func (c *Client) GetResourceList(resourceType string) (list []interface{}, err error) { + url := "/cluster/resources" if resourceType != "" { - endpoint = fmt.Sprintf("%s?type=%s", endpoint, resourceType) + url = url + "?type=" + resourceType } - err = c.GetJsonRetryable(endpoint, &list, 3) - return + return c.GetItemListInterfaceArray(url) } -func (c *Client) GetVmList() (list map[string]interface{}, err error) { - list, err = c.GetResourceList("vm") - return +func (c *Client) GetVmList() (map[string]interface{}, error) { + list, err := c.GetResourceList("vm") + return map[string]interface{}{"data": list}, err } func (c *Client) CheckVmRef(vmr *VmRef) (err error) { From 8c03d7147d7bd87e97a0316025b96b5ee9f88e29 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:08:40 +0000 Subject: [PATCH 158/191] refactor: add constant to improve readability --- proxmox/client.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index 71957574..f7130239 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -156,6 +156,8 @@ func (c *Client) GetNodeList() (list map[string]interface{}, err error) { return } +const resourceListGuest string = "vm" + // GetResourceList returns a list of all enabled proxmox resources. // For resource types that can be in a disabled state, disabled resources // will not be returned @@ -169,7 +171,7 @@ func (c *Client) GetResourceList(resourceType string) (list []interface{}, err e } func (c *Client) GetVmList() (map[string]interface{}, error) { - list, err := c.GetResourceList("vm") + list, err := c.GetResourceList(resourceListGuest) return map[string]interface{}{"data": list}, err } From b2c6f98d46f7b8225e3607cb9ecfccb7f575b8b4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:12:29 +0000 Subject: [PATCH 159/191] Add TODO --- proxmox/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/proxmox/client.go b/proxmox/client.go index f7130239..d955c152 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -170,6 +170,7 @@ func (c *Client) GetResourceList(resourceType string) (list []interface{}, err e return c.GetItemListInterfaceArray(url) } +// TODO deprecate once nothing uses this anymore, use GetResourceList() instead func (c *Client) GetVmList() (map[string]interface{}, error) { list, err := c.GetResourceList(resourceListGuest) return map[string]interface{}{"data": list}, err From 033e99f6da2b13ff173aeb7989240918fef6250f Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:20:05 +0000 Subject: [PATCH 160/191] feat: add new ListGuests() --- proxmox/config_guest.go | 112 ++++++++++++++++ proxmox/config_guest_test.go | 239 +++++++++++++++++++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100644 proxmox/config_guest_test.go diff --git a/proxmox/config_guest.go b/proxmox/config_guest.go index fc5a0cc8..c969b1ef 100644 --- a/proxmox/config_guest.go +++ b/proxmox/config_guest.go @@ -2,10 +2,113 @@ package proxmox import ( "strconv" + "strings" ) // All code LXC and Qemu have in common should be placed here. +type GuestResource struct { + CpuCores uint `json:"cpu_cores"` + CpuUsage float64 `json:"cpu_usage"` + DiskReadTotal uint `json:"disk_read"` + DiskSizeInBytes uint `json:"disk_size"` + DiskUsedInBytes uint `json:"disk_used"` + DiskWriteTotal uint `json:"disk_write"` + HaState string `json:"hastate"` // TODO custom type? + Id uint `json:"id"` + MemoryTotalInBytes uint `json:"memory_total"` + MemoryUsedInBytes uint `json:"memory_used"` + Name string `json:"name"` // TODO custom type + NetworkIn uint `json:"network_in"` + NetworkOut uint `json:"network_out"` + Node string `json:"node"` // TODO custom type + Pool string `json:"pool"` // TODO custom type + Status string `json:"status"` // TODO custom type? + Tags []string `json:"tags"` // TODO custom type + Template bool `json:"template"` + Type GuestType `json:"type"` + UptimeInSeconds uint `json:"uptime"` +} + +// https://pve.proxmox.com/pve-docs/api-viewer/#/cluster/resources +func (GuestResource) mapToStruct(params []interface{}) []GuestResource { + if len(params) == 0 { + return nil + } + resources := make([]GuestResource, len(params)) + for i := range params { + tmpParams := params[i].(map[string]interface{}) + if _, isSet := tmpParams["maxcpu"]; isSet { + resources[i].CpuCores = uint(tmpParams["maxcpu"].(float64)) + } + if _, isSet := tmpParams["cpu"]; isSet { + resources[i].CpuUsage = tmpParams["cpu"].(float64) + } + if _, isSet := tmpParams["diskread"]; isSet { + resources[i].DiskReadTotal = uint(tmpParams["diskread"].(float64)) + } + if _, isSet := tmpParams["maxdisk"]; isSet { + resources[i].DiskSizeInBytes = uint(tmpParams["maxdisk"].(float64)) + } + if _, isSet := tmpParams["disk"]; isSet { + resources[i].DiskUsedInBytes = uint(tmpParams["disk"].(float64)) + } + if _, isSet := tmpParams["diskwrite"]; isSet { + resources[i].DiskWriteTotal = uint(tmpParams["diskwrite"].(float64)) + } + if _, isSet := tmpParams["hastate"]; isSet { + resources[i].HaState = tmpParams["hastate"].(string) + } + if _, isSet := tmpParams["vmid"]; isSet { + resources[i].Id = uint(tmpParams["vmid"].(float64)) + } + if _, isSet := tmpParams["maxmem"]; isSet { + resources[i].MemoryTotalInBytes = uint(tmpParams["maxmem"].(float64)) + } + if _, isSet := tmpParams["mem"]; isSet { + resources[i].MemoryUsedInBytes = uint(tmpParams["mem"].(float64)) + } + if _, isSet := tmpParams["name"]; isSet { + resources[i].Name = tmpParams["name"].(string) + } + if _, isSet := tmpParams["netin"]; isSet { + resources[i].NetworkIn = uint(tmpParams["netin"].(float64)) + } + if _, isSet := tmpParams["netout"]; isSet { + resources[i].NetworkOut = uint(tmpParams["netout"].(float64)) + } + if _, isSet := tmpParams["node"]; isSet { + resources[i].Node = tmpParams["node"].(string) + } + if _, isSet := tmpParams["pool"]; isSet { + resources[i].Pool = tmpParams["pool"].(string) + } + if _, isSet := tmpParams["status"]; isSet { + resources[i].Status = tmpParams["status"].(string) + } + if _, isSet := tmpParams["tags"]; isSet { + resources[i].Tags = strings.Split(tmpParams["tags"].(string), ";") + } + if _, isSet := tmpParams["template"]; isSet { + resources[i].Template = Itob(int(tmpParams["template"].(float64))) + } + if _, isSet := tmpParams["type"]; isSet { + resources[i].Type = GuestType(tmpParams["type"].(string)) + } + if _, isSet := tmpParams["uptime"]; isSet { + resources[i].UptimeInSeconds = uint(tmpParams["uptime"].(float64)) + } + } + return resources +} + +type GuestType string + +const ( + GuestLXC GuestType = "lxc" + GuestQemu GuestType = "qemu" +) + // Check if there are any pending changes that require a reboot to be applied. func GuestHasPendingChanges(vmr *VmRef, client *Client) (bool, error) { params, err := pendingGuestConfigFromApi(vmr, client) @@ -25,6 +128,15 @@ func GuestReboot(vmr *VmRef, client *Client) (err error) { return } +// List all guest the user has viewing rights for in the cluster +func ListGuests(client *Client) ([]GuestResource, error) { + list, err := client.GetResourceList("vm") + if err != nil { + return nil, err + } + return GuestResource{}.mapToStruct(list), nil +} + func pendingGuestConfigFromApi(vmr *VmRef, client *Client) ([]interface{}, error) { err := vmr.nilCheck() if err != nil { diff --git a/proxmox/config_guest_test.go b/proxmox/config_guest_test.go new file mode 100644 index 00000000..c2328d47 --- /dev/null +++ b/proxmox/config_guest_test.go @@ -0,0 +1,239 @@ +package proxmox + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_GuestResource_mapToStruct(t *testing.T) { + tests := []struct { + name string + input []interface{} + output []GuestResource + }{ + {name: "CpuCores", + input: []interface{}{map[string]interface{}{"maxcpu": float64(10)}}, + output: []GuestResource{{CpuCores: 10}}, + }, + {name: "CpuUsage", + input: []interface{}{map[string]interface{}{"cpu": float64(3.141592653589793)}}, + output: []GuestResource{{CpuUsage: 3.141592653589793}}, + }, + {name: "DiskReadTotal", + input: []interface{}{map[string]interface{}{"diskread": float64(1637428)}}, + output: []GuestResource{{DiskReadTotal: 1637428}}, + }, + {name: "DiskSizeInBytes", + input: []interface{}{map[string]interface{}{"maxdisk": float64(8589934592)}}, + output: []GuestResource{{DiskSizeInBytes: 8589934592}}, + }, + {name: "DiskUsedInBytes", + input: []interface{}{map[string]interface{}{"disk": float64(1073741824)}}, + output: []GuestResource{{DiskUsedInBytes: 1073741824}}, + }, + {name: "DiskWriteTotal", + input: []interface{}{map[string]interface{}{"diskwrite": float64(1690811)}}, + output: []GuestResource{{DiskWriteTotal: 1690811}}, + }, + {name: "HaState", + input: []interface{}{map[string]interface{}{"hastate": "started"}}, + output: []GuestResource{{HaState: "started"}}, + }, + {name: "Id", + input: []interface{}{map[string]interface{}{"vmid": float64(100)}}, + output: []GuestResource{{Id: 100}}, + }, + {name: "MemoryTotalInBytes", + input: []interface{}{map[string]interface{}{"maxmem": float64(2147483648)}}, + output: []GuestResource{{MemoryTotalInBytes: 2147483648}}, + }, + {name: "MemoryUsedInBytes", + input: []interface{}{map[string]interface{}{"mem": float64(1048576)}}, + output: []GuestResource{{MemoryUsedInBytes: 1048576}}, + }, + {name: "Name", + input: []interface{}{map[string]interface{}{"name": "test-vm1"}}, + output: []GuestResource{{Name: "test-vm1"}}, + }, + {name: "NetworkIn", + input: []interface{}{map[string]interface{}{"netin": float64(23884639)}}, + output: []GuestResource{{NetworkIn: 23884639}}, + }, + {name: "NetworkOut", + input: []interface{}{map[string]interface{}{"netout": float64(1000123465987)}}, + output: []GuestResource{{NetworkOut: 1000123465987}}, + }, + {name: "Node", + input: []interface{}{map[string]interface{}{"node": "pve1"}}, + output: []GuestResource{{Node: "pve1"}}, + }, + {name: "Pool", + input: []interface{}{map[string]interface{}{"pool": "Production"}}, + output: []GuestResource{{Pool: "Production"}}, + }, + {name: "Status", + input: []interface{}{map[string]interface{}{"status": "running"}}, + output: []GuestResource{{Status: "running"}}, + }, + {name: "Tags", + input: []interface{}{map[string]interface{}{"tags": "tag1;tag2;tag3"}}, + output: []GuestResource{{Tags: []string{"tag1", "tag2", "tag3"}}}, + }, + {name: "Template", + input: []interface{}{map[string]interface{}{"template": float64(1)}}, + output: []GuestResource{{Template: true}}, + }, + {name: "Type", + input: []interface{}{map[string]interface{}{"type": "qemu"}}, + output: []GuestResource{{Type: GuestQemu}}, + }, + {name: "UptimeInSeconds", + input: []interface{}{map[string]interface{}{"uptime": float64(72169)}}, + output: []GuestResource{{UptimeInSeconds: 72169}}, + }, + {name: "[]GuestResource", + input: []interface{}{ + map[string]interface{}{ + "maxcpu": float64(10), + "cpu": float64(3.141592653589793), + "diskread": float64(1637428), + "maxdisk": float64(8589934592), + "disk": float64(0), + "diskwrite": float64(1690811), + "hastate": "started", + "vmid": float64(100), + "maxmem": float64(2147483648), + "mem": float64(1048576), + "name": "test-vm1", + "netin": float64(23884639), + "netout": float64(1000123465987), + "node": "pve1", + "pool": "Production", + "status": "running", + "tags": "tag1;tag2;tag3", + "template": float64(0), + "type": "qemu", + "uptime": float64(72169), + }, + map[string]interface{}{ + "maxcpu": float64(50), + "cpu": float64(0.141592653589793), + "diskread": float64(857324), + "maxdisk": float64(9743424), + "disk": float64(23234), + "diskwrite": float64(78347843754), + "hastate": "", + "vmid": float64(100000), + "maxmem": float64(946856732535), + "mem": float64(1342), + "name": "dev-vm1", + "netin": float64(2331323424), + "netout": float64(88775378423476), + "node": "pve2", + "pool": "Development", + "status": "running", + "tags": "dev", + "template": float64(0), + "type": "lxc", + "uptime": float64(88678345), + }, + map[string]interface{}{ + "maxcpu": float64(1), + "cpu": float64(0), + "diskread": float64(846348234), + "disk": float64(0), + "maxdisk": float64(56742482484), + "diskwrite": float64(3432), + "hastate": "", + "vmid": float64(999), + "maxmem": float64(727345728374), + "mem": float64(68467234324), + "name": "template-linux", + "netin": float64(23884639), + "netout": float64(1000123465987), + "node": "node3", + "pool": "Templates", + "status": "stopped", + "tags": "template", + "template": float64(1), + "type": "qemu", + "uptime": float64(0), + }, + }, + output: []GuestResource{ + { + CpuCores: 10, + CpuUsage: 3.141592653589793, + DiskReadTotal: 1637428, + DiskUsedInBytes: 0, + DiskSizeInBytes: 8589934592, + DiskWriteTotal: 1690811, + HaState: "started", + Id: 100, + MemoryTotalInBytes: 2147483648, + MemoryUsedInBytes: 1048576, + Name: "test-vm1", + NetworkIn: 23884639, + NetworkOut: 1000123465987, + Node: "pve1", + Pool: "Production", + Status: "running", + Tags: []string{"tag1", "tag2", "tag3"}, + Template: false, + Type: GuestQemu, + UptimeInSeconds: 72169, + }, + { + CpuCores: 50, + CpuUsage: 0.141592653589793, + DiskReadTotal: 857324, + DiskUsedInBytes: 23234, + DiskSizeInBytes: 9743424, + DiskWriteTotal: 78347843754, + HaState: "", + Id: 100000, + MemoryTotalInBytes: 946856732535, + MemoryUsedInBytes: 1342, + Name: "dev-vm1", + NetworkIn: 2331323424, + NetworkOut: 88775378423476, + Node: "pve2", + Pool: "Development", + Status: "running", + Tags: []string{"dev"}, + Template: false, + Type: GuestLXC, + UptimeInSeconds: 88678345, + }, + { + CpuCores: 1, + CpuUsage: 0, + DiskReadTotal: 846348234, + DiskUsedInBytes: 0, + DiskSizeInBytes: 56742482484, + DiskWriteTotal: 3432, + HaState: "", + Id: 999, + MemoryTotalInBytes: 727345728374, + MemoryUsedInBytes: 68467234324, + Name: "template-linux", + NetworkIn: 23884639, + NetworkOut: 1000123465987, + Node: "node3", + Pool: "Templates", + Status: "stopped", + Tags: []string{"template"}, + Template: true, + Type: GuestQemu, + UptimeInSeconds: 0, + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.output, GuestResource{}.mapToStruct(test.input), test.name) + }) + } +} From 7dd6a1982a9756a8c766fed5816855aa9d89a0e4 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:20:36 +0000 Subject: [PATCH 161/191] refactor: command list guests --- cli/command/list/list-guests.go | 7 ++++++- cli/command/list/list.go | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cli/command/list/list-guests.go b/cli/command/list/list-guests.go index 35ebf702..7fe8364e 100644 --- a/cli/command/list/list-guests.go +++ b/cli/command/list/list-guests.go @@ -1,6 +1,8 @@ package list import ( + "github.com/Telmate/proxmox-api-go/cli" + "github.com/Telmate/proxmox-api-go/proxmox" "github.com/spf13/cobra" ) @@ -9,7 +11,10 @@ var list_qemuguestsCmd = &cobra.Command{ Short: "Prints a list of Qemu/Lxc Guests in raw json format", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - listRaw("Guests") + c := cli.NewClient() + guests, err := proxmox.ListGuests(c) + cli.LogFatalListing("Guests", err) + cli.PrintRawJson(listCmd.OutOrStdout(), guests) }, } diff --git a/cli/command/list/list.go b/cli/command/list/list.go index 51a872ee..c57ae9f7 100644 --- a/cli/command/list/list.go +++ b/cli/command/list/list.go @@ -23,8 +23,6 @@ func listRaw(IDtype string) { list, err = c.GetAcmeAccountList() case "AcmePlugins": list, err = c.GetAcmePluginList() - case "Guests": - list, err = c.GetVmList() case "MetricServers": list, err = c.GetMetricsServerList() case "Nodes": From 226571fb60c6b2635e63bf6c5842e6a231db5dbd Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:06:29 +0000 Subject: [PATCH 162/191] refactor: move error check lower in the call stack --- proxmox/client.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index d955c152..3e9d057a 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -188,11 +188,7 @@ func (c *Client) GetVmInfo(vmr *VmRef) (vmInfo map[string]interface{}, err error if resp, err = c.GetVmList(); err != nil { return } - vms, ok := resp["data"].([]interface{}) - if !ok { - err = fmt.Errorf("failed to cast response to list, resp: %v", resp) - return - } + vms := resp["data"].([]interface{}) for vmii := range vms { vm := vms[vmii].(map[string]interface{}) if int(vm["vmid"].(float64)) == vmr.vmId { @@ -1957,7 +1953,11 @@ func (c *Client) GetItemListInterfaceArray(url string) ([]interface{}, error) { if err != nil { return nil, err } - return list["data"].([]interface{}), nil + data, ok := list["data"].([]interface{}) + if !ok { + return nil, fmt.Errorf("failed to cast response to list, resp: %v", list) + } + return data, nil } func (c *Client) GetItemList(url string) (list map[string]interface{}, err error) { From 3d9eaac812a455a3bddefb20019396542e96e283 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:24:43 +0000 Subject: [PATCH 163/191] refactor: better code reuse --- proxmox/client.go | 11 ++++------- proxmox/config_qemu.go | 3 +-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/proxmox/client.go b/proxmox/client.go index 3e9d057a..6219156d 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -184,11 +184,10 @@ func (c *Client) CheckVmRef(vmr *VmRef) (err error) { } func (c *Client) GetVmInfo(vmr *VmRef) (vmInfo map[string]interface{}, err error) { - var resp map[string]interface{} - if resp, err = c.GetVmList(); err != nil { + vms, err := c.GetResourceList(resourceListGuest) + if err != nil { return } - vms := resp["data"].([]interface{}) for vmii := range vms { vm := vms[vmii].(map[string]interface{}) if int(vm["vmid"].(float64)) == vmr.vmId { @@ -218,11 +217,10 @@ func (c *Client) GetVmRefByName(vmName string) (vmr *VmRef, err error) { } func (c *Client) GetVmRefsByName(vmName string) (vmrs []*VmRef, err error) { - resp, err := c.GetVmList() + vms, err := c.GetResourceList(resourceListGuest) if err != nil { return } - vms := resp["data"].([]interface{}) for vmii := range vms { vm := vms[vmii].(map[string]interface{}) if vm["name"] != nil && vm["name"].(string) == vmName { @@ -871,11 +869,10 @@ func (c *Client) GetNextID(currentID int) (nextID int, err error) { // VMIdExists - If you pass an VMID that exists it will return true, otherwise it wil return false func (c *Client) VMIdExists(vmID int) (exists bool, err error) { - resp, err := c.GetVmList() + vms, err := c.GetResourceList(resourceListGuest) if err != nil { return } - vms := resp["data"].([]interface{}) for vmii := range vms { vm := vms[vmii].(map[string]interface{}) if vmID == int(vm["vmid"].(float64)) { diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index 42156f52..aeedcd42 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -1289,8 +1289,7 @@ func RemoveSshForwardUsernet(vmr *VmRef, client *Client) (err error) { } func MaxVmId(client *Client) (max int, err error) { - resp, err := client.GetVmList() - vms := resp["data"].([]interface{}) + vms, err := client.GetResourceList(resourceListGuest) max = 100 for vmii := range vms { vm := vms[vmii].(map[string]interface{}) From 13cf13f57b45116a679c263ecb3d0966371e86aa Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:33:55 +0000 Subject: [PATCH 164/191] Update TODO --- proxmox/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index 6219156d..b6b365d0 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -170,7 +170,7 @@ func (c *Client) GetResourceList(resourceType string) (list []interface{}, err e return c.GetItemListInterfaceArray(url) } -// TODO deprecate once nothing uses this anymore, use GetResourceList() instead +// TODO deprecate once nothing uses this anymore, use ListGuests() instead func (c *Client) GetVmList() (map[string]interface{}, error) { list, err := c.GetResourceList(resourceListGuest) return map[string]interface{}{"data": list}, err From 34293114d9937dd458d8a13e72a5db55521340a2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:59:01 +0000 Subject: [PATCH 165/191] make `CreateSnapshot()` use `VmRef1 as input --- cli/command/create/create-snapshot.go | 8 +++++++- proxmox/snapshot.go | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cli/command/create/create-snapshot.go b/cli/command/create/create-snapshot.go index 74b80eec..510feeb1 100644 --- a/cli/command/create/create-snapshot.go +++ b/cli/command/create/create-snapshot.go @@ -23,7 +23,13 @@ var ( VmState: memory, } memory = false - err = config.CreateSnapshot(cli.NewClient(), uint(id)) + client := cli.NewClient() + vmr := proxmox.NewVmRef(id) + _, err = client.GetVmInfo(vmr) + if err != nil { + return + } + err = config.CreateSnapshot(client, vmr) if err != nil { return } diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index e58a43e9..de253bb4 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -20,10 +20,9 @@ func (config *ConfigSnapshot) mapToApiValues() map[string]interface{} { } } -func (config *ConfigSnapshot) CreateSnapshot(c *Client, guestId uint) (err error) { +func (config *ConfigSnapshot) CreateSnapshot(c *Client, vmr *VmRef) (err error) { params := config.mapToApiValues() - vmr := NewVmRef(int(guestId)) - _, err = c.GetVmInfo(vmr) + err = c.CheckVmRef(vmr) if err != nil { return } From 621fed467c590b38485944a427e751927c3bb35a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Thu, 8 Jun 2023 09:39:56 +0000 Subject: [PATCH 166/191] Change pointer to normal variable --- proxmox/snapshot.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index de253bb4..c89e7c0d 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -12,7 +12,7 @@ type ConfigSnapshot struct { VmState bool `json:"ram,omitempty"` } -func (config *ConfigSnapshot) mapToApiValues() map[string]interface{} { +func (config ConfigSnapshot) mapToApiValues() map[string]interface{} { return map[string]interface{}{ "snapname": config.Name, "description": config.Description, @@ -20,7 +20,7 @@ func (config *ConfigSnapshot) mapToApiValues() map[string]interface{} { } } -func (config *ConfigSnapshot) CreateSnapshot(c *Client, vmr *VmRef) (err error) { +func (config ConfigSnapshot) CreateSnapshot(c *Client, vmr *VmRef) (err error) { params := config.mapToApiValues() err = c.CheckVmRef(vmr) if err != nil { From 516556234691810e37e67664dcadc6a87c336b41 Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Sat, 10 Jun 2023 10:00:06 +0300 Subject: [PATCH 167/191] No need for an ApiToken field --- proxmox/client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index baa87d58..548c2c8f 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -30,7 +30,6 @@ type Client struct { ApiUrl string Username string Password string - ApiToken string Otp string TaskTimeout int } From 4e89538a6b826b820679c80a6828488eb4dfdd3d Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Fri, 16 Jun 2023 17:22:59 +0300 Subject: [PATCH 168/191] making the linter happy --- proxmox/config_sdn_subnet.go | 2 +- proxmox/config_sdn_vnet.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxmox/config_sdn_subnet.go b/proxmox/config_sdn_subnet.go index 63bcd9bf..0f9a2a81 100644 --- a/proxmox/config_sdn_subnet.go +++ b/proxmox/config_sdn_subnet.go @@ -75,7 +75,7 @@ func (c *ConfigSDNSubnet) Validate(vnet, id string, create bool, client *Client) return } if !vnetExists { - return fmt.Errorf("Subnet must be created in an existing vnet. Vnet (%s) wasn't found", vnet) + return fmt.Errorf("subnet must be created in an existing vnet. vnet (%s) wasn't found", vnet) } exists, err := client.CheckSDNSubnetExistance(vnet, id) if err != nil { diff --git a/proxmox/config_sdn_vnet.go b/proxmox/config_sdn_vnet.go index 7c6bf72c..f7793226 100644 --- a/proxmox/config_sdn_vnet.go +++ b/proxmox/config_sdn_vnet.go @@ -72,12 +72,12 @@ func (c *ConfigSDNVNet) Validate(id string, create bool, client *Client) (err er return } if !zoneExists { - return fmt.Errorf("VNet must be associated to an existing zone. Zone %s could not be found.", c.Zone) + return fmt.Errorf("vnet must be associated to an existing zone. zone %s could not be found", c.Zone) } if c.Alias != "" { - regex, _ := regexp.Compile(`^(?^i:[\(\)-_.\w\d\s]{0,256})$`) + regex, _ := regexp.Compile(`^(?i:[\(\)-_.\w\d\s]{0,256})$`) if !regex.Match([]byte(c.Alias)) { - return fmt.Errorf(`Alias must match the validation regular expression: ^(?^i:[\(\)-_.\w\d\s]{0,256})$`) + return fmt.Errorf(`alias must match the validation regular expression: ^(?i:[\(\)-_.\w\d\s]{0,256})$`) } } err = ValidateIntGreater(0, c.Tag, "tag") From c3bd7b7b2747f7877aa3045fb30f3c18d1a1f3d5 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:56:10 +0000 Subject: [PATCH 169/191] test: added for api `wwn` setting --- proxmox/config_qemu_test.go | 532 ++++++++++++++++++++++-------------- 1 file changed, 332 insertions(+), 200 deletions(-) diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 68f7a8f3..96acaf96 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -67,16 +67,17 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - EmulateSSD: true, - Format: format_Raw, - Replicate: true, - Serial: "558485ef-478", - Size: 32, - Storage: "Test", - }}}}}, - output: map[string]interface{}{"ide0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=558485ef-478,ssd=1"}, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + Format: format_Raw, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + WorldWideName: "0x5000D31000C9876F", + }}}}}, + output: map[string]interface{}{"ide0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=558485ef-478,ssd=1,wwn=0x5000D31000C9876F"}, }, {name: "Create Disks.Ide.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -186,6 +187,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{Storage: "Test"}}}}}, output: map[string]interface{}{"ide0": "Test:0,backup=0,replicate=0"}, }, + {name: "Create Disks.Ide.Disk_X.Disk.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{WorldWideName: "0x5001234000F876AB"}}}}}, + output: map[string]interface{}{"ide0": ",backup=0,replicate=0,wwn=0x5001234000F876AB"}, + }, // Create Disks.Ide.Disk_X.Passthrough {name: "Create Disks.Ide.Disk_X.Passthrough All", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ @@ -201,14 +206,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - Replicate: true, - Serial: "test-serial_757465-gdg", + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "test-serial_757465-gdg", + WorldWideName: "0x500CBA2000D76543", }}}}}, - output: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + output: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1,wwn=0x500CBA2000D76543"}, }, {name: "Create Disks.Ide.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -310,6 +316,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{Serial: "test-serial_757465-gdg"}}}}}, output: map[string]interface{}{"ide3": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, }, + {name: "Create Disks.Ide.Disk_X.Passthrough.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_3: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{WorldWideName: "0x500FED1000B65432"}}}}}, + output: map[string]interface{}{"ide3": ",backup=0,replicate=0,wwn=0x500FED1000B65432"}, + }, // Create Disks.Sata {name: "Create Disks.Sata.Disk_X.Disk_X.CdRom none", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{CdRom: &QemuCdRom{}}}}}, @@ -342,16 +352,17 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Replicate: true, - Serial: "ab_C-12_3", - Size: 32, - Storage: "Test", - }}}}}, - output: map[string]interface{}{"sata0": "Test:32,aio=native,cache=unsafe,discard=on,format=qcow2,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=ab_C-12_3,ssd=1"}, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Replicate: true, + Serial: "ab_C-12_3", + Size: 32, + Storage: "Test", + WorldWideName: "0x5009876000A321DC", + }}}}}, + output: map[string]interface{}{"sata0": "Test:32,aio=native,cache=unsafe,discard=on,format=qcow2,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=ab_C-12_3,ssd=1,wwn=0x5009876000A321DC"}, }, {name: "Create Disks.Sata.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -461,6 +472,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{Storage: "Test"}}}}}, output: map[string]interface{}{"sata5": "Test:0,backup=0,replicate=0"}, }, + {name: "Create Disks.Sata.Disk_X.Disk.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{WorldWideName: "0x500DCBA500E23456"}}}}}, + output: map[string]interface{}{"sata0": ",backup=0,replicate=0,wwn=0x500DCBA500E23456"}, + }, // Create Disks.Sata.Disk_X.Passthrough {name: "Create Disks.Sata.Disk_X.Passthrough All", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ @@ -476,14 +491,15 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - Replicate: true, - Serial: "test-serial_757465-gdg", + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + Serial: "test-serial_757465-gdg", + WorldWideName: "0x5007892000C4321A", }}}}}, - output: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1"}, + output: map[string]interface{}{"sata0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,serial=test-serial_757465-gdg,ssd=1,wwn=0x5007892000C4321A"}, }, {name: "Create Disks.Sata.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -585,6 +601,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{Serial: "test-serial_757465-gdg"}}}}}, output: map[string]interface{}{"sata5": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, }, + {name: "Create Disks.Sata.Disk_X.Passthrough.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{WorldWideName: "0x5001ABE000987654"}}}}}, + output: map[string]interface{}{"sata5": ",backup=0,replicate=0,wwn=0x5001ABE000987654"}, + }, // Create Disks.Scsi {name: "Create Disks.Scsi.CdRom none", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{CdRom: &QemuCdRom{}}}}}, @@ -617,18 +637,19 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - EmulateSSD: true, - Format: format_Raw, - IOThread: true, - ReadOnly: true, - Replicate: true, - Serial: "558485ef-478", - Size: 32, - Storage: "Test", - }}}}}, - output: map[string]interface{}{"scsi0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,ssd=1"}, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + Format: format_Raw, + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + WorldWideName: "0x500D567800BAC321", + }}}}}, + output: map[string]interface{}{"scsi0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,ssd=1,wwn=0x500D567800BAC321"}, }, {name: "Create Disks.Scsi.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -746,6 +767,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_26: &QemuScsiStorage{Disk: &QemuScsiDisk{Storage: "Test"}}}}}, output: map[string]interface{}{"scsi26": "Test:0,backup=0,replicate=0"}, }, + {name: "Create Disks.Scsi.Disk_X.Disk.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_27: &QemuScsiStorage{Disk: &QemuScsiDisk{WorldWideName: "0x500EF32100D76589"}}}}}, + output: map[string]interface{}{"scsi27": ",backup=0,replicate=0,wwn=0x500EF32100D76589"}, + }, // Create Disks.Scsi.Passthrough {name: "Create Disks.Scsi.Disk_X.Passthrough All", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ @@ -761,16 +786,17 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - IOThread: true, - ReadOnly: true, - Replicate: true, - Serial: "test-serial_757465-gdg", - }}}}}, - output: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,ssd=1"}, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "test-serial_757465-gdg", + WorldWideName: "0x500BCA3000F09876", + }}}}}, + output: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,ssd=1,wwn=0x500BCA3000F09876"}, }, {name: "Create Disks.Scsi.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -880,6 +906,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_25: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{Serial: "test-serial_757465-gdg"}}}}}, output: map[string]interface{}{"scsi25": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, }, + {name: "Create Disks.Scsi.Disk_X.Passthrough.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_25: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{WorldWideName: "0x5004DC0100E239C7"}}}}}, + output: map[string]interface{}{"scsi25": ",backup=0,replicate=0,wwn=0x5004DC0100E239C7"}, + }, // Create Disks.VirtIO {name: "Create Disks.VirtIO.Disk_X.CdRom none", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{CdRom: &QemuCdRom{}}}}}, @@ -912,17 +942,18 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - Format: format_Raw, - IOThread: true, - ReadOnly: true, - Replicate: true, - Serial: "558485ef-478", - Size: 32, - Storage: "Test", - }}}}}, - output: map[string]interface{}{"virtio0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478"}, + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: format_Raw, + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "558485ef-478", + Size: 32, + Storage: "Test", + WorldWideName: "0x500A7B0800F345D2", + }}}}}, + output: map[string]interface{}{"virtio0": "Test:32,aio=native,cache=directsync,discard=on,format=raw,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=558485ef-478,wwn=0x500A7B0800F345D2"}, }, {name: "Create Disks.VirtIO.Disk_X.Disk.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{AsyncIO: QemuDiskAsyncIO_Native}}}}}, @@ -1044,6 +1075,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_9: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{Storage: "Test"}}}}}, output: map[string]interface{}{"virtio9": "Test:0,backup=0,replicate=0"}, }, + {name: "Create Disks.VirtIO.Disk_X.Disk.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_10: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{WorldWideName: "0x5005FED000B87632"}}}}}, + output: map[string]interface{}{"virtio10": ",backup=0,replicate=0,wwn=0x5005FED000B87632"}, + }, // Create Disks.VirtIO.Disk_X.Passthrough {name: "Create Disks.VirtIO.Disk_X.Passthrough All", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ @@ -1059,15 +1094,16 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: uint89, BurstDuration: 4, Concurrent: uint23}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - IOThread: true, - ReadOnly: true, - Replicate: true, - Serial: "test-serial_757465-gdg", + Cache: QemuDiskCache_Unsafe, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: true, + Serial: "test-serial_757465-gdg", + WorldWideName: "0x500C329500A1EFAB", }}}}}, - output: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg"}, + output: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,cache=unsafe,discard=on,iops_rd=34,iops_rd_max=78,iops_rd_max_length=3,iops_wr=23,iops_wr_max=89,iops_wr_max_length=4,iothread=1,mbps_rd=10.30,mbps_rd_max=99.20,mbps_wr=45.23,mbps_wr_max=79.23,ro=1,serial=test-serial_757465-gdg,wwn=0x500C329500A1EFAB"}, }, {name: "Create Disks.VirtIO.Disk_X.Passthrough.AsyncIO", config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: QemuDiskAsyncIO_Threads}}}}}, @@ -1173,6 +1209,10 @@ func Test_ConfigQemu_mapToApiValues(t *testing.T) { config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_7: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{Serial: "test-serial_757465-gdg"}}}}}, output: map[string]interface{}{"virtio7": ",backup=0,replicate=0,serial=test-serial_757465-gdg"}, }, + {name: "Create Disks.VirtIO.Disk_X.Passthrough.WorldWideName", + config: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_8: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{WorldWideName: "0x500D41A600C67853"}}}}}, + output: map[string]interface{}{"virtio8": ",backup=0,replicate=0,wwn=0x500D41A600C67853"}, + }, // Create Iso {name: "Create Iso", config: &ConfigQemu{Iso: &IsoFile{Storage: "test", File: "file.iso"}}, @@ -2349,7 +2389,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Ide Disk ALL", - input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1,wwn=0x500F753600A987E1"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -2363,19 +2403,20 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, }, }, - Cache: QemuDiskCache_WriteThrough, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint53, - Replicate: false, - Serial: "disk-9763", - Size: 1032, - Storage: "test2", + Cache: QemuDiskCache_WriteThrough, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + Replicate: false, + Serial: "disk-9763", + Size: 1032, + Storage: "test2", + WorldWideName: "0x500F753600A987E1", }}}}}, }, {name: "Disks Ide Disk ALL LinkedClone", - input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1"}, + input: map[string]interface{}{"ide1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-53.qcow2,aio=io_uring,backup=0,cache=writethrough,discard=on,iops_rd=12,iops_rd_max=13,iops_rd_max_length=4,iops_wr=15,iops_wr_max=14,iops_wr_max_length=5,mbps_rd=1.46,mbps_rd_max=3.57,mbps_wr=2.68,mbps_wr_max=4.55,replicate=0,serial=disk-9763,size=1032G,ssd=1,wwn=0x500679CE00B1DAF4"}, output: &ConfigQemu{ LinkedVmId: 110, Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ @@ -2391,16 +2432,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 14, BurstDuration: 5, Concurrent: 15}, }, }, - Cache: QemuDiskCache_WriteThrough, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint53, - LinkedDiskId: &uint1, - Replicate: false, - Serial: "disk-9763", - Size: 1032, - Storage: "test2", + Cache: QemuDiskCache_WriteThrough, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + LinkedDiskId: &uint1, + Replicate: false, + Serial: "disk-9763", + Size: 1032, + Storage: "test2", + WorldWideName: "0x500679CE00B1DAF4", }}}}}, }, {name: "Disks Ide Disk aio", @@ -2610,6 +2652,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Ide Disk wwn", + input: map[string]interface{}{"ide1": "test2:100/vm-100-disk-53.qcow2,wwn=0x500DB82100C6FA59"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint53, + Replicate: true, + Storage: "test2", + WorldWideName: "0x500DB82100C6FA59", + }}}}}, + }, // Disks Ide Passthrough {name: "Disks Ide Passthrough", input: map[string]interface{}{"ide0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, @@ -2620,7 +2673,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Ide Passthrough All", - input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1,wwn=0x500CBE4300D978A6"}, output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -2634,13 +2687,14 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - Replicate: false, - Serial: "disk-9763", - Size: 1, + Cache: QemuDiskCache_Unsafe, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + Serial: "disk-9763", + Size: 1, + WorldWideName: "0x500CBE4300D978A6", }}}}}, }, {name: "Disks Ide Passthrough aio", @@ -2803,6 +2857,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Ide Passthrough wwn", + input: map[string]interface{}{"ide1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,wwn=0x5005AC1200F643B8"}, + output: &ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + WorldWideName: "0x5005AC1200F643B8", + }}}}}, + }, // Disks Sata CdRom {name: "Disks Sata CdRom none", input: map[string]interface{}{"sata5": "none,media=cdrom"}, @@ -2840,7 +2903,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Sata Disk ALL", - input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"sata1": "test2:100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1,wwn=0x500DFA8900E3C641"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ AsyncIO: QemuDiskAsyncIO_Native, Backup: false, @@ -2854,19 +2917,20 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_None, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint47, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + WorldWideName: "0x500DFA8900E3C641", }}}}}, }, {name: "Disks Sata Disk ALL LinkedClone", - input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"sata1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-47.qcow2,aio=native,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=32G,ssd=1,wwn=0x5003B97600A8F2D4"}, output: &ConfigQemu{ LinkedVmId: 110, Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Disk: &QemuSataDisk{ @@ -2882,16 +2946,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_None, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint47, - LinkedDiskId: &uint1, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + LinkedDiskId: &uint1, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + WorldWideName: "0x5003B97600A8F2D4", }}}}}, }, {name: "Disks Sata Disk aio", @@ -3105,6 +3170,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks Sata Disk wwn", + input: map[string]interface{}{"sata5": "test2:100/vm-100-disk-47.qcow2,wwn=0x5001E48A00D567C9"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Disk: &QemuSataDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint47, + Replicate: true, + Storage: "test2", + WorldWideName: "0x5001E48A00D567C9", + }}}}}, + }, // Disks Sata Passthrough {name: "Disks Sata Passthrough", input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, @@ -3115,7 +3191,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Sata Passthrough All", - input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=5,iops_wr=11,iops_wr_max=13,iops_wr_max_length=4,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"sata1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=5,iops_wr=11,iops_wr_max=13,iops_wr_max_length=4,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,serial=disk-9763,size=1G,ssd=1,wwn=500E9FBC00F2A6D3"}, output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -3129,13 +3205,14 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 4, Concurrent: 11}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - Replicate: false, - Serial: "disk-9763", - Size: 1, + Cache: QemuDiskCache_DirectSync, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: false, + Serial: "disk-9763", + Size: 1, + WorldWideName: "500E9FBC00F2A6D3", }}}}}, }, {name: "Disks Sata Passthrough aio", @@ -3298,6 +3375,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Sata Passthrough wwn", + input: map[string]interface{}{"sata5": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,wwn=0x5004D2EF00C8B57A"}, + output: &ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_5: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + WorldWideName: "0x5004D2EF00C8B57A", + }}}}}, + }, // Disks Scsi CdRom {name: "Disks Scsi CdRom none", input: map[string]interface{}{"scsi30": "none,media=cdrom"}, @@ -3335,7 +3421,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Scsi Disk ALL", - input: map[string]interface{}{"scsi1": "test:100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"scsi1": "test:100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1,wwn=0x500AF18700E9CD25"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -3349,21 +3435,22 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_WriteBack, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint2, - IOThread: true, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test", + Cache: QemuDiskCache_WriteBack, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test", + WorldWideName: "0x500AF18700E9CD25", }}}}}, }, {name: "Disks Scsi Disk ALL LinkedClone", - input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1"}, + input: map[string]interface{}{"scsi1": "test:110/base-110-disk-1.qcow2/100/vm-100-disk-2.qcow2,aio=threads,backup=0,cache=writeback,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,ssd=1,wwn=0x500879DC00F3BE6A"}, output: &ConfigQemu{ LinkedVmId: 110, Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Disk: &QemuScsiDisk{ @@ -3379,18 +3466,19 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_WriteBack, - Discard: true, - EmulateSSD: true, - Format: QemuDiskFormat_Qcow2, - Id: uint2, - IOThread: true, - LinkedDiskId: &uint1, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test", + Cache: QemuDiskCache_WriteBack, + Discard: true, + EmulateSSD: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + IOThread: true, + LinkedDiskId: &uint1, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test", + WorldWideName: "0x500879DC00F3BE6A", }}}}}, }, {name: "Disks Scsi Disk aio", @@ -3622,6 +3710,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test", }}}}}, }, + {name: "Disks Scsi Disk wwn", + input: map[string]interface{}{"scsi19": "test:100/vm-100-disk-2.qcow2,wwn=0x500E265400A1F3D7"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint2, + Replicate: true, + Storage: "test", + WorldWideName: "0x500E265400A1F3D7", + }}}}}, + }, // Disks Scsi Passthrough {name: "Disks Scsi Passthrough", input: map[string]interface{}{"scsi0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, @@ -3632,7 +3731,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks Scsi Passthrough All", - input: map[string]interface{}{"scsi1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,ssd=1"}, + input: map[string]interface{}{"scsi1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=threads,backup=0,cache=none,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,ssd=1,wwn=500CB15600D8FE32"}, output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_1: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ AsyncIO: QemuDiskAsyncIO_Threads, Backup: false, @@ -3646,15 +3745,16 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_None, - Discard: true, - EmulateSSD: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - IOThread: true, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 1, + Cache: QemuDiskCache_None, + Discard: true, + EmulateSSD: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 1, + WorldWideName: "500CB15600D8FE32", }}}}}, }, {name: "Disks Scsi Passthrough aio", @@ -3835,6 +3935,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Replicate: true, }}}}}, }, + {name: "Disks Scsi Passthrough wwn", + input: map[string]interface{}{"scsi19": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,wwn=0x5009A4FC00B7C613"}, + output: &ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_19: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + WorldWideName: "0x5009A4FC00B7C613", + }}}}}, + }, // VirtIO CdRom {name: "Disks VirtIO CdRom none", input: map[string]interface{}{"virtio11": "none,media=cdrom"}, @@ -3872,7 +3981,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks VirtIO Disk ALL", - input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + input: map[string]interface{}{"virtio1": "test2:100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,wwn=0x50015B3900F8EAD2"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ AsyncIO: QemuDiskAsyncIO_IOuring, Backup: false, @@ -3886,20 +3995,21 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - Format: QemuDiskFormat_Qcow2, - Id: uint31, - IOThread: true, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + WorldWideName: "0x50015B3900F8EAD2", }}}}}, }, {name: "Disks VirtIO Disk ALL LinkedClone", - input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G"}, + input: map[string]interface{}{"virtio1": "test2:110/base-110-disk-1.qcow2/100/vm-100-disk-31.qcow2,aio=io_uring,backup=0,cache=directsync,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=2,iops_wr=11,iops_wr_max=13,iops_wr_max_length=3,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=32G,wwn=0x500FA2D000C69587"}, output: &ConfigQemu{ LinkedVmId: 110, Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ @@ -3915,17 +4025,18 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 3, Concurrent: 11}, }, }, - Cache: QemuDiskCache_DirectSync, - Discard: true, - Format: QemuDiskFormat_Qcow2, - Id: uint31, - IOThread: true, - LinkedDiskId: &uint1, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 32, - Storage: "test2", + Cache: QemuDiskCache_DirectSync, + Discard: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + IOThread: true, + LinkedDiskId: &uint1, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 32, + Storage: "test2", + WorldWideName: "0x500FA2D000C69587", }}}}}, }, {name: "Disks VirtIO Disk aio", @@ -4150,6 +4261,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Storage: "test2", }}}}}, }, + {name: "Disks VirtIO Disk wwn", + input: map[string]interface{}{"virtio2": "test2:100/vm-100-disk-31.qcow2,wwn=0x500D3FAB00B4E672"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Backup: true, + Format: QemuDiskFormat_Qcow2, + Id: uint31, + Replicate: true, + Storage: "test2", + WorldWideName: "0x500D3FAB00B4E672", + }}}}}, + }, // Disks VirtIO Passthrough {name: "Disks VirtIO Passthrough", input: map[string]interface{}{"virtio0": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8"}, @@ -4160,7 +4282,7 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}}, }, {name: "Disks VirtIO Passthrough ALL", - input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G"}, + input: map[string]interface{}{"virtio1": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,aio=native,backup=0,cache=unsafe,discard=on,iops_rd=10,iops_rd_max=12,iops_rd_max_length=4,iops_wr=11,iops_wr_max=13,iops_wr_max_length=5,iothread=1,mbps_rd=1.51,mbps_rd_max=3.51,mbps_wr=2.51,mbps_wr_max=4.51,replicate=0,ro=1,serial=disk-9763,size=1G,wwn=0x500B6ED600F1C945"}, output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_1: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ AsyncIO: QemuDiskAsyncIO_Native, Backup: false, @@ -4174,14 +4296,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { WriteLimit: QemuDiskBandwidthIopsLimit{Burst: 13, BurstDuration: 5, Concurrent: 11}, }, }, - Cache: QemuDiskCache_Unsafe, - Discard: true, - File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", - IOThread: true, - ReadOnly: true, - Replicate: false, - Serial: "disk-9763", - Size: 1, + Cache: QemuDiskCache_Unsafe, + Discard: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + IOThread: true, + ReadOnly: true, + Replicate: false, + Serial: "disk-9763", + Size: 1, + WorldWideName: "0x500B6ED600F1C945", }}}}}, }, {name: "Disks VirtIO Passthrough aio", @@ -4353,6 +4476,15 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { Size: 1, }}}}}, }, + {name: "Disks VirtIO Passthrough wwn", + input: map[string]interface{}{"virtio2": "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8,wwn=0x5008FA6500D9C8B3"}, + output: &ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_2: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ + Backup: true, + File: "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi8", + Replicate: true, + WorldWideName: "0x5008FA6500D9C8B3", + }}}}}, + }, // Iso {name: "Iso", input: map[string]interface{}{"ide2": "local:iso/debian-11.0.0-amd64-netinst.iso,media=cdrom,size=377M"}, From eb08997b596a8a192ced85f51d66e7930ffeb82c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 21 Jun 2023 20:00:22 +0000 Subject: [PATCH 170/191] feat: add logic for converting `wwn` Added logic for converting `wwn` between API and struct. --- proxmox/config_qemu_disk.go | 14 ++- proxmox/config_qemu_disk_ide.go | 148 +++++++++++++------------ proxmox/config_qemu_disk_sata.go | 148 +++++++++++++------------ proxmox/config_qemu_disk_scsi.go | 172 +++++++++++++++-------------- proxmox/config_qemu_disk_virtio.go | 160 ++++++++++++++------------- 5 files changed, 337 insertions(+), 305 deletions(-) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 8b31db7f..0176e719 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -187,8 +187,9 @@ type qemuDisk struct { Serial QemuDiskSerial Size uint // TODO custom type - Storage string // Only set for Disk - Type qemuDiskType + Storage string // Only set for Disk + Type qemuDiskType + WorldWideName QemuWorldWideName } const ( @@ -288,7 +289,9 @@ func (disk qemuDisk) mapToApiValues(vmID, LinkedVmId uint, currentStorage string if disk.Type != virtIO && disk.EmulateSSD { settings = settings + ",ssd=1" } - + if disk.WorldWideName != "" { + settings = settings + ",wwn=" + string(disk.WorldWideName) + } return } @@ -418,6 +421,9 @@ func (qemuDisk) mapToStruct(diskData string, settings map[string]interface{}, li if value, isSet := settings["ssd"]; isSet { disk.EmulateSSD, _ = strconv.ParseBool(value.(string)) } + if value, isSet := settings["wwn"]; isSet { + disk.WorldWideName = QemuWorldWideName(value.(string)) + } return &disk } @@ -1008,6 +1014,8 @@ type qemuUpdateChanges struct { Resize []qemuDiskResize } +type QemuWorldWideName string + func diskSubtypeSet(set bool) error { if set { return errors.New(Error_QemuDisk_MutuallyExclusive) diff --git a/proxmox/config_qemu_disk_ide.go b/proxmox/config_qemu_disk_ide.go index ed019ae3..52b495f5 100644 --- a/proxmox/config_qemu_disk_ide.go +++ b/proxmox/config_qemu_disk_ide.go @@ -6,38 +6,40 @@ import ( ) type QemuIdeDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` + WorldWideName QemuWorldWideName `json:"wwn"` } func (disk *QemuIdeDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - LinkedDiskId: disk.LinkedDiskId, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: ide, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedDiskId: disk.LinkedDiskId, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: ide, + WorldWideName: disk.WorldWideName, } } @@ -135,30 +137,32 @@ func (disks QemuIdeDisks) validate() (numberOfCloudInitDevices uint8, err error) } type QemuIdePassthrough struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - File string `json:"file"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect + WorldWideName QemuWorldWideName `json:"wwn"` } func (passthrough *QemuIdePassthrough) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: ide, + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: ide, + WorldWideName: passthrough.WorldWideName, } } @@ -225,32 +229,34 @@ func (QemuIdeStorage) mapToStruct(param string, LinkedVmId *uint) *QemuIdeStorag } if tmpDisk.File == "" { return &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - LinkedDiskId: tmpDisk.LinkedDiskId, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedDiskId: tmpDisk.LinkedDiskId, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + WorldWideName: tmpDisk.WorldWideName, }} } return &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - File: tmpDisk.File, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + WorldWideName: tmpDisk.WorldWideName, }} } diff --git a/proxmox/config_qemu_disk_sata.go b/proxmox/config_qemu_disk_sata.go index d1c4b584..e4e89c42 100644 --- a/proxmox/config_qemu_disk_sata.go +++ b/proxmox/config_qemu_disk_sata.go @@ -6,38 +6,40 @@ import ( ) type QemuSataDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + LinkedDiskId *uint `json:"linked"` //LinkedClone is only returned and setting it has no effect + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` + WorldWideName QemuWorldWideName `json:"wwn"` } func (disk *QemuSataDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - LinkedDiskId: disk.LinkedDiskId, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: sata, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + LinkedDiskId: disk.LinkedDiskId, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: sata, + WorldWideName: disk.WorldWideName, } } @@ -147,30 +149,32 @@ func (disks QemuSataDisks) validate() (numberOfCloudInitDevices uint8, err error } type QemuSataPassthrough struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - File string `json:"file"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect + WorldWideName QemuWorldWideName `json:"wwn"` } func (passthrough *QemuSataPassthrough) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: sata, + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: sata, + WorldWideName: passthrough.WorldWideName, } } @@ -237,32 +241,34 @@ func (QemuSataStorage) mapToStruct(param string, LinkedVmId *uint) *QemuSataStor } if tmpDisk.File == "" { return &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - LinkedDiskId: tmpDisk.LinkedDiskId, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + LinkedDiskId: tmpDisk.LinkedDiskId, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + WorldWideName: tmpDisk.WorldWideName, }} } return &QemuSataStorage{Passthrough: &QemuSataPassthrough{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - File: tmpDisk.File, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + WorldWideName: tmpDisk.WorldWideName, }} } diff --git a/proxmox/config_qemu_disk_scsi.go b/proxmox/config_qemu_disk_scsi.go index 3ad5a1ea..e68ee370 100644 --- a/proxmox/config_qemu_disk_scsi.go +++ b/proxmox/config_qemu_disk_scsi.go @@ -6,42 +6,44 @@ import ( ) type QemuScsiDisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` + WorldWideName QemuWorldWideName `json:"wwn"` } func (disk *QemuScsiDisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - EmulateSSD: disk.EmulateSSD, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - LinkedDiskId: disk.LinkedDiskId, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: scsi, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + EmulateSSD: disk.EmulateSSD, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedDiskId: disk.LinkedDiskId, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: scsi, + WorldWideName: disk.WorldWideName, } } @@ -301,34 +303,36 @@ func (disks QemuScsiDisks) validate() (numberOfCloudInitDevices uint8, err error } type QemuScsiPassthrough struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - EmulateSSD bool `json:"emulatessd"` - File string `json:"file"` - IOThread bool `json:"iothread"` - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + EmulateSSD bool `json:"emulatessd"` + File string `json:"file"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect + WorldWideName QemuWorldWideName `json:"wwn"` } func (passthrough *QemuScsiPassthrough) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - EmulateSSD: passthrough.EmulateSSD, - File: passthrough.File, - IOThread: passthrough.IOThread, - ReadOnly: passthrough.ReadOnly, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: scsi, + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + EmulateSSD: passthrough.EmulateSSD, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: scsi, + WorldWideName: passthrough.WorldWideName, } } @@ -395,36 +399,38 @@ func (QemuScsiStorage) mapToStruct(param string, LinkedVmId *uint) *QemuScsiStor } if tmpDisk.File == "" { return &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - LinkedDiskId: tmpDisk.LinkedDiskId, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedDiskId: tmpDisk.LinkedDiskId, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + WorldWideName: tmpDisk.WorldWideName, }} } return &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - EmulateSSD: tmpDisk.EmulateSSD, - File: tmpDisk.File, - IOThread: tmpDisk.IOThread, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + EmulateSSD: tmpDisk.EmulateSSD, + File: tmpDisk.File, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + WorldWideName: tmpDisk.WorldWideName, }} } diff --git a/proxmox/config_qemu_disk_virtio.go b/proxmox/config_qemu_disk_virtio.go index 4962d5e2..40973ca7 100644 --- a/proxmox/config_qemu_disk_virtio.go +++ b/proxmox/config_qemu_disk_virtio.go @@ -6,40 +6,42 @@ import ( ) type QemuVirtIODisk struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - Format QemuDiskFormat `json:"format"` - Id uint `json:"id"` //Id is only returned and setting it has no effect - IOThread bool `json:"iothread"` - LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` - Storage string `json:"storage"` + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + Format QemuDiskFormat `json:"format"` + Id uint `json:"id"` //Id is only returned and setting it has no effect + IOThread bool `json:"iothread"` + LinkedDiskId *uint `json:"linked"` //LinkedCloneId is only returned and setting it has no effect + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` + Storage string `json:"storage"` + WorldWideName QemuWorldWideName `json:"wwn"` } func (disk *QemuVirtIODisk) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: disk.AsyncIO, - Backup: disk.Backup, - Bandwidth: disk.Bandwidth, - Cache: disk.Cache, - Discard: disk.Discard, - Disk: true, - Format: disk.Format, - Id: disk.Id, - IOThread: disk.IOThread, - LinkedDiskId: disk.LinkedDiskId, - ReadOnly: disk.ReadOnly, - Replicate: disk.Replicate, - Serial: disk.Serial, - Size: disk.Size, - Storage: disk.Storage, - Type: virtIO, + AsyncIO: disk.AsyncIO, + Backup: disk.Backup, + Bandwidth: disk.Bandwidth, + Cache: disk.Cache, + Discard: disk.Discard, + Disk: true, + Format: disk.Format, + Id: disk.Id, + IOThread: disk.IOThread, + LinkedDiskId: disk.LinkedDiskId, + ReadOnly: disk.ReadOnly, + Replicate: disk.Replicate, + Serial: disk.Serial, + Size: disk.Size, + Storage: disk.Storage, + Type: virtIO, + WorldWideName: disk.WorldWideName, } } @@ -209,32 +211,34 @@ func (disks QemuVirtIODisks) validate() (numberOfCloudInitDevices uint8, err err } type QemuVirtIOPassthrough struct { - AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` - Backup bool `json:"backup"` - Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` - Cache QemuDiskCache `json:"cache,omitempty"` - Discard bool `json:"discard"` - File string `json:"file"` - IOThread bool `json:"iothread"` - ReadOnly bool `json:"readonly"` - Replicate bool `json:"replicate"` - Serial QemuDiskSerial `json:"serial,omitempty"` - Size uint `json:"size"` //size is only returned and setting it has no effect + AsyncIO QemuDiskAsyncIO `json:"asyncio,omitempty"` + Backup bool `json:"backup"` + Bandwidth QemuDiskBandwidth `json:"bandwidth,omitempty"` + Cache QemuDiskCache `json:"cache,omitempty"` + Discard bool `json:"discard"` + File string `json:"file"` + IOThread bool `json:"iothread"` + ReadOnly bool `json:"readonly"` + Replicate bool `json:"replicate"` + Serial QemuDiskSerial `json:"serial,omitempty"` + Size uint `json:"size"` //size is only returned and setting it has no effect + WorldWideName QemuWorldWideName `json:"wwn"` } func (passthrough *QemuVirtIOPassthrough) convertDataStructure() *qemuDisk { return &qemuDisk{ - AsyncIO: passthrough.AsyncIO, - Backup: passthrough.Backup, - Bandwidth: passthrough.Bandwidth, - Cache: passthrough.Cache, - Discard: passthrough.Discard, - File: passthrough.File, - IOThread: passthrough.IOThread, - ReadOnly: passthrough.ReadOnly, - Replicate: passthrough.Replicate, - Serial: passthrough.Serial, - Type: virtIO, + AsyncIO: passthrough.AsyncIO, + Backup: passthrough.Backup, + Bandwidth: passthrough.Bandwidth, + Cache: passthrough.Cache, + Discard: passthrough.Discard, + File: passthrough.File, + IOThread: passthrough.IOThread, + ReadOnly: passthrough.ReadOnly, + Replicate: passthrough.Replicate, + Serial: passthrough.Serial, + Type: virtIO, + WorldWideName: passthrough.WorldWideName, } } @@ -301,34 +305,36 @@ func (QemuVirtIOStorage) mapToStruct(param string, LinkedVmId *uint) *QemuVirtIO } if tmpDisk.File == "" { return &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - Format: tmpDisk.Format, - Id: tmpDisk.Id, - IOThread: tmpDisk.IOThread, - LinkedDiskId: tmpDisk.LinkedDiskId, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, - Storage: tmpDisk.Storage, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + Format: tmpDisk.Format, + Id: tmpDisk.Id, + IOThread: tmpDisk.IOThread, + LinkedDiskId: tmpDisk.LinkedDiskId, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + Storage: tmpDisk.Storage, + WorldWideName: tmpDisk.WorldWideName, }} } return &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ - AsyncIO: tmpDisk.AsyncIO, - Backup: tmpDisk.Backup, - Bandwidth: tmpDisk.Bandwidth, - Cache: tmpDisk.Cache, - Discard: tmpDisk.Discard, - File: tmpDisk.File, - IOThread: tmpDisk.IOThread, - ReadOnly: tmpDisk.ReadOnly, - Replicate: tmpDisk.Replicate, - Serial: tmpDisk.Serial, - Size: tmpDisk.Size, + AsyncIO: tmpDisk.AsyncIO, + Backup: tmpDisk.Backup, + Bandwidth: tmpDisk.Bandwidth, + Cache: tmpDisk.Cache, + Discard: tmpDisk.Discard, + File: tmpDisk.File, + IOThread: tmpDisk.IOThread, + ReadOnly: tmpDisk.ReadOnly, + Replicate: tmpDisk.Replicate, + Serial: tmpDisk.Serial, + Size: tmpDisk.Size, + WorldWideName: tmpDisk.WorldWideName, }} } From 0c3dcc2958491e8e5022e6020fc9c43cde672db2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:20:06 +0000 Subject: [PATCH 171/191] test: added for `QemuWorldWideName` --- proxmox/config_qemu_disk_test.go | 22 +++ proxmox/config_qemu_test.go | 140 +++++++++++++----- .../test_data_qemu/type_QemuWorldWideName.go | 112 ++++++++++++++ 3 files changed, 234 insertions(+), 40 deletions(-) create mode 100644 test/data/test_data_qemu/type_QemuWorldWideName.go diff --git a/proxmox/config_qemu_disk_test.go b/proxmox/config_qemu_disk_test.go index 2f5c23ac..4080e082 100644 --- a/proxmox/config_qemu_disk_test.go +++ b/proxmox/config_qemu_disk_test.go @@ -836,3 +836,25 @@ func Test_QemuStorages_markDiskChanges(t *testing.T) { }) } } + +func Test_QemuWorldWideName_Validate(t *testing.T) { + testRunes := struct { + legal []string + illegal []string + }{ + legal: test_data_qemu.QemuWorldWideName_Legal(), + illegal: test_data_qemu.QemuWorldWideName_Illegal(), + } + for _, test := range testRunes.legal { + name := "legal:" + test + t.Run(name, func(*testing.T) { + require.NoError(t, QemuWorldWideName(test).Validate(), name) + }) + } + for _, test := range testRunes.illegal { + name := "illegal:" + test + t.Run(name, func(*testing.T) { + require.Error(t, QemuWorldWideName(test).Validate(), name) + }) + } +} diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 96acaf96..5c4ddd8b 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -4649,36 +4649,40 @@ func Test_ConfigQemu_Validate(t *testing.T) { {name: "Valid Disks Disk", input: ConfigQemu{Disks: &QemuStorages{ Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Bandwidth: BandwidthValid0, - Cache: QemuDiskCache_DirectSync, - Format: QemuDiskFormat_Raw, - Size: 32, - Storage: "test", + AsyncIO: QemuDiskAsyncIO_IOuring, + Bandwidth: BandwidthValid0, + Cache: QemuDiskCache_DirectSync, + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "test", + WorldWideName: "0x500A1B2C3D4E5F60", }}}, Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ - AsyncIO: QemuDiskAsyncIO_Native, - Bandwidth: BandwidthValid1, - Cache: QemuDiskCache_None, - Format: QemuDiskFormat_Cow, - Size: 1, - Storage: "test", + AsyncIO: QemuDiskAsyncIO_Native, + Bandwidth: BandwidthValid1, + Cache: QemuDiskCache_None, + Format: QemuDiskFormat_Cow, + Size: 1, + Storage: "test", + WorldWideName: "0x500F123456789ABC", }}}, Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{ - AsyncIO: QemuDiskAsyncIO_Threads, - Bandwidth: BandwidthValid2, - Cache: QemuDiskCache_WriteBack, - Format: QemuDiskFormat_Qcow2, - Size: 10, - Storage: "test", + AsyncIO: QemuDiskAsyncIO_Threads, + Bandwidth: BandwidthValid2, + Cache: QemuDiskCache_WriteBack, + Format: QemuDiskFormat_Qcow2, + Size: 10, + Storage: "test", + WorldWideName: "0x5009876543210DEF", }}}, VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ - AsyncIO: "", - Bandwidth: BandwidthValid3, - Cache: "", - Format: QemuDiskFormat_Vmdk, - Size: 1024, - Storage: "test", + AsyncIO: "", + Bandwidth: BandwidthValid3, + Cache: "", + Format: QemuDiskFormat_Vmdk, + Size: 1024, + Storage: "test", + WorldWideName: "0x500C0D0E0F101112", }}}, }}, }, @@ -4686,28 +4690,32 @@ func Test_ConfigQemu_Validate(t *testing.T) { {name: "Valid Disks Passthrough", input: ConfigQemu{Disks: &QemuStorages{ Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{ - AsyncIO: QemuDiskAsyncIO_IOuring, - Bandwidth: BandwidthValid3, - Cache: QemuDiskCache_DirectSync, - File: "test", + AsyncIO: QemuDiskAsyncIO_IOuring, + Bandwidth: BandwidthValid3, + Cache: QemuDiskCache_DirectSync, + File: "test", + WorldWideName: "0x5001A2B3C4D5E6F7", }}}, Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{ - AsyncIO: QemuDiskAsyncIO_Native, - Bandwidth: BandwidthValid2, - Cache: "", - File: "test", + AsyncIO: QemuDiskAsyncIO_Native, + Bandwidth: BandwidthValid2, + Cache: "", + File: "test", + WorldWideName: "0x500B0A0908070605", }}}, Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{ - AsyncIO: QemuDiskAsyncIO_Threads, - Bandwidth: BandwidthValid1, - Cache: QemuDiskCache_WriteBack, - File: "test", + AsyncIO: QemuDiskAsyncIO_Threads, + Bandwidth: BandwidthValid1, + Cache: QemuDiskCache_WriteBack, + File: "test", + WorldWideName: "0x500F1E2D3C4B5A69", }}}, VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{ - AsyncIO: "", - Bandwidth: BandwidthValid0, - Cache: QemuDiskCache_WriteThrough, - File: "test", + AsyncIO: "", + Bandwidth: BandwidthValid0, + Cache: QemuDiskCache_WriteThrough, + File: "test", + WorldWideName: "0x5004A3B2C1D0E0F1", }}}, }}, }, @@ -5292,6 +5300,15 @@ func Test_ConfigQemu_Validate(t *testing.T) { }}}}}, err: errors.New(Error_QemuDisk_Storage), }, + {name: `Invalid Disks Disk Ide errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Disk: &QemuIdeDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "Test", + WorldWideName: "0xG123456789ABCDE", + }}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Disk Sata {name: `Invalid Disks Disk Sata QemuDiskFormat("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{}}}}}, @@ -5370,6 +5387,15 @@ func Test_ConfigQemu_Validate(t *testing.T) { }}}}}, err: errors.New(Error_QemuDisk_Storage), }, + {name: `Invalid Disks Disk Sata errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Disk: &QemuSataDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "Test", + WorldWideName: "500A1B2C3D4E5F60", + }}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Disk Scsi {name: `Invalid Disks Disk Scsi QemuDiskFormat("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Disk: &QemuScsiDisk{}}}}}, @@ -5448,6 +5474,15 @@ func Test_ConfigQemu_Validate(t *testing.T) { }}}}}, err: errors.New(Error_QemuDisk_Storage), }, + {name: `Invalid Disks Disk Scsi errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_16: &QemuScsiStorage{Disk: &QemuScsiDisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "Test", + WorldWideName: "0x5009876543210DEFG", + }}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Disk VirtIO {name: `Invalid Disks Disk VirtIO QemuDiskFormat("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{}}}}}, @@ -5526,6 +5561,15 @@ func Test_ConfigQemu_Validate(t *testing.T) { }}}}}, err: errors.New(Error_QemuDisk_Storage), }, + {name: `Invalid Disks Disk VirtIO errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Disk: &QemuVirtIODisk{ + Format: QemuDiskFormat_Raw, + Size: 32, + Storage: "Test", + WorldWideName: "500C0D0E0F10111", + }}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Passthrough Ide {name: `Invalid Disks Passthrough Ide QemuDiskAsyncIO("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{AsyncIO: "invalid"}}}}}, @@ -5579,6 +5623,10 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_0: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, err: errors.New(Error_QemuDiskSerial_IllegalLength), }, + {name: `Invalid Disks Passthrough Ide errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Ide: &QemuIdeDisks{Disk_1: &QemuIdeStorage{Passthrough: &QemuIdePassthrough{File: "/dev/disk/by-id/scsi1", WorldWideName: "5001A2B3C4D5E6F7"}}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Passthrough Sata {name: `Invalid Disks Passthrough Sata QemuDiskAsyncIO("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{AsyncIO: "invalid"}}}}}, @@ -5632,6 +5680,10 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_0: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, err: errors.New(Error_QemuDiskSerial_IllegalLength), }, + {name: `Invalid Disks Passthrough Sata errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Sata: &QemuSataDisks{Disk_1: &QemuSataStorage{Passthrough: &QemuSataPassthrough{File: "/dev/disk/by-id/scsi1", WorldWideName: "0x500B0A09080706050"}}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Passthrough Scsi {name: `Invalid Disks Passthrough Scsi QemuDiskAsyncIO("").Error()`, input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_0: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{AsyncIO: "invalid"}}}}}, @@ -5685,6 +5737,10 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_12: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, err: errors.New(Error_QemuDiskSerial_IllegalLength), }, + {name: `Invalid Disks Passthrough Scsi errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{Scsi: &QemuScsiDisks{Disk_13: &QemuScsiStorage{Passthrough: &QemuScsiPassthrough{File: "/dev/disk/by-id/scsi1", WorldWideName: "500F1E2D3C4B5A69!"}}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, // Invalid Disks Passthrough VirtIO {name: `Invalid Disks Passthrough VirtIO QemuDiskAsyncIO("").Error()`, input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_0: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{AsyncIO: "invalid"}}}}}, @@ -5738,6 +5794,10 @@ func Test_ConfigQemu_Validate(t *testing.T) { input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_12: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: "/dev/disk/by-id/scsi1", Serial: QemuDiskSerial(test_data_qemu.QemuDiskSerial_Max_Illegal())}}}}}, err: errors.New(Error_QemuDiskSerial_IllegalLength), }, + {name: `Invalid Disks Passthrough VirtIO errors.New(Error_QemuWorldWideName_Invalid)`, + input: ConfigQemu{Disks: &QemuStorages{VirtIO: &QemuVirtIODisks{Disk_13: &QemuVirtIOStorage{Passthrough: &QemuVirtIOPassthrough{File: "/dev/disk/by-id/scsi1", WorldWideName: "0x5004A3B2C1D0E0F1#"}}}}}, + err: errors.New(Error_QemuWorldWideName_Invalid), + }, } for _, test := range testData { t.Run(test.name, func(*testing.T) { diff --git a/test/data/test_data_qemu/type_QemuWorldWideName.go b/test/data/test_data_qemu/type_QemuWorldWideName.go new file mode 100644 index 00000000..3c10ad18 --- /dev/null +++ b/test/data/test_data_qemu/type_QemuWorldWideName.go @@ -0,0 +1,112 @@ +package test_data_qemu + +func QemuWorldWideName_Legal() []string { + return []string{ + "", + "0x8F14641E7F4B27D6", + "0x43135F8B89D7E9D9", + "0x0C92E69424B1609D", + "0x55049C1C8DA23E50", + "0x9F70557F3A5D09BC", + "0x2C04D021E89E41FD", + "0x3D7071A0976895A0", + "0x7914EAC8244DB5A2", + "0x30A8A0D6A24B9563", + "0x1DA1CDD690CE41FE", + "0x79D8D06D781F8D16", + "0x821F901FEFEA690F", + "0x13A9628C95F19A4F", + "0x6D9E42EFDE9EB1D1", + "0x2D7167DFCD4C5B48", + "0x5F792FE5AD87513D", + "0x9B9B9E1508D0B8B9", + "0x1C179E26A7B1A040", + "0x4C5DB30D3E9B1C0A", + "0x7AED3B1457078D6A", + "0x6F64A1761AB78825", + "0x5D8EDD9C5B95C478", + "0x3C2857A432EC3E9B", + "0x1EE0843512C6B6BE", + "0x45272E11136D0B4F", + "0x08C7D3C6E51EF776", + "0x28B3B1B41D53A770", + "0x4A937430E15BCE2B", + "0x183B7321B0F62A80", + "0x38C24563EAD1C289", + "0x5B1DAF347BEEF152", + "0x0E60D51E5CB50D1A", + "0x30B2393E28A3EDE4", + "0x47954C1E3B5CAB46", + "0x68C0D3D016D68C23", + "0x933BB8B523C8ACF6", + "0x1F25C742A9FBE60D", + "0x09B3EFEF2C88FFAC", + "0x8B0D9F41A15B7FA6", + "0x6E2A86B5E950857C", + "0x3F90A27347DC4F36", + "0x17619BC0F9F02DBB", + "0x31D591AE875E8712", + "0x787E9C1D6D25C12F", + "0x586AF239D285F6D5", + "0x961DDAA98CC9A58C", + "0x241FD8850C9CCDF2", + "0x9A4D8EAEBC50E3A9", + "0x6A33FEC7390CFC45", + "0x1B3CE82A3F2C8EFA", + "0x42C22809DB71A0E1", + } +} + +func QemuWorldWideName_Illegal() []string { + return []string{ + "0x44556677EEFF", + "0x09876:54321", + "0x1AB2:3C4D", + "586AF239D285F6D5,", + "0x0A0B0C0D0E0F", + "0x12:34:56:78", + "0x98:76:54:32", + "0x00:11:22:33:44:55:66:77", + "0xAA:BB:CC:DD:EE:FF", + "0x1:2:3:4:5:6:7", + "0122334455667788", + "x9A9B9C9D9E9F", + "0x1A1B1C1D1E1F", + "0x11223344AABBCC", + "x44556677", + "0x0987:6543", + "0x1A:B2:3C:4D", + "0x55667788", + "0x0A:0B:0C:0D", + "0x12:34:56", + "0x98:76:54", + "0x00:11:22:33:44:55:66", + "0xAA:BB:CC:DD:EE", + "1:2:3:4:5:6", + "0x11223344556677", + "9A9B9C9D9E9", + "0x1A1B1C1D1E", + "0x11223344AABBC", + "0x44556677EE", + "0x098765:54321", + "0x1AB:2C4D", + "0x556677889", + "0x0A0B0C0D0", + "12:34:5:78", + "0x98:76:54:3", + "0x00:11:22:33:44:55:6", + "0xAA:BB:CC:DD:EE:F", + "1:2:3:4:5:6:7", + "0x1122334455667", + "0x9A9B9C9D9E", + "0x1A1B1C1D1", + "11223344AABB", + "0x44556677EEF", + "0x09876:5432", + "0x1AB2:C4D", + "0x5566778899,", + "0x0A0B0C0D", + "0x12:34:56:7", + "x98:76:54:2", + } +} From 32d9a2dcbed4a5720e35eba0e051061d0ed66948 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:21:13 +0000 Subject: [PATCH 172/191] feat: validator `QemuWorldWideName` --- proxmox/config_qemu_disk.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/proxmox/config_qemu_disk.go b/proxmox/config_qemu_disk.go index 0176e719..8539e1c5 100644 --- a/proxmox/config_qemu_disk.go +++ b/proxmox/config_qemu_disk.go @@ -443,6 +443,9 @@ func (disk *qemuDisk) validate() (err error) { if err = disk.Serial.Validate(); err != nil { return } + if err = disk.WorldWideName.Validate(); err != nil { + return + } if disk.Disk { // disk if err = disk.Format.Validate(); err != nil { @@ -1016,6 +1019,17 @@ type qemuUpdateChanges struct { type QemuWorldWideName string +const Error_QemuWorldWideName_Invalid string = "world wide name should be prefixed with 0x followed by 8 hexadecimal values" + +var regexp_QemuWorldWideName = regexp.MustCompile(`^0x[0-9A-Fa-f]{16}$`) + +func (wwn QemuWorldWideName) Validate() error { + if wwn == "" || regexp_QemuWorldWideName.MatchString(string(wwn)) { + return nil + } + return errors.New(Error_QemuWorldWideName_Invalid) +} + func diskSubtypeSet(set bool) error { if set { return errors.New(Error_QemuDisk_MutuallyExclusive) From a8777ab3342bc6b4ba18afc997829d80363b4033 Mon Sep 17 00:00:00 2001 From: zinefer Date: Fri, 7 Jul 2023 21:58:04 -0600 Subject: [PATCH 173/191] Bugfix: Allow the creation of bind mounts for lxc containers This commit essentially makes size optional for a mount specified by volume. --- proxmox/config_lxc.go | 1 + proxmox/config_qemu.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/proxmox/config_lxc.go b/proxmox/config_lxc.go index cbfb1808..c91d6f87 100644 --- a/proxmox/config_lxc.go +++ b/proxmox/config_lxc.go @@ -473,6 +473,7 @@ func (config ConfigLxc) mapToApiValues() map[string]interface{} { // add mp to lxc parameters mpID := mpConfMap["slot"] mpName := fmt.Sprintf("mp%v", mpID) + paramMap[mpName] = FormatDiskParam(mpConfMap) } diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index aeedcd42..83b54d76 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -1380,7 +1380,10 @@ func FormatDiskParam(disk QemuDevice) string { if volume, ok := disk["volume"]; ok && volume != "" { diskConfParam = append(diskConfParam, volume.(string)) - diskConfParam = append(diskConfParam, fmt.Sprintf("size=%v", disk["size"])) + + if size, ok := disk["size"]; ok && size != "" { + diskConfParam = append(diskConfParam, fmt.Sprintf("size=%v", disk["size"])) + } } else { volumeInit := fmt.Sprintf("%v:%v", disk["storage"], DiskSizeGB(disk["size"])) diskConfParam = append(diskConfParam, volumeInit) From 938fbc2900f310bc69dd1614ae7c8e37738665b1 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 15:06:33 +0000 Subject: [PATCH 174/191] refactor: put in alphabetical order --- proxmox/config_qemu.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index aeedcd42..11f080c3 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -48,7 +48,6 @@ type ConfigQemu struct { Description string `json:"description,omitempty"` Disks *QemuStorages `json:"disks,omitempty"` EFIDisk QemuDevice `json:"efidisk,omitempty"` // TODO should be a struct - RNGDrive QemuDevice `json:"rng0,omitempty"` // TODO should be a struct FullClone *int `json:"fullclone,omitempty"` // TODO should probably be a bool HaGroup string `json:"hagroup,omitempty"` HaState string `json:"hastate,omitempty"` // TODO should be custom type with enum @@ -80,6 +79,7 @@ type ConfigQemu struct { QemuUsbs QemuDevices `json:"usb,omitempty"` // TODO should be a struct QemuVcpus int `json:"vcpus,omitempty"` // TODO should be uint QemuVga QemuDevice `json:"vga,omitempty"` // TODO should be a struct + RNGDrive QemuDevice `json:"rng0,omitempty"` // TODO should be a struct Scsihw string `json:"scsihw,omitempty"` // TODO should be custom type with enum Searchdomain string `json:"searchdomain,omitempty"` // TODO should be part of a cloud-init struct (cloud-init option) Smbios1 string `json:"smbios1,omitempty"` // TODO should be custom type with enum? From bd6f10d241dedbbd8aa98b8e74a1a5b946b37866 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:44:45 +0000 Subject: [PATCH 175/191] feat: Add nil check --- proxmox/client.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proxmox/client.go b/proxmox/client.go index 548c2c8f..81a959ba 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -34,6 +34,10 @@ type Client struct { TaskTimeout int } +const ( + VmRef_Error_Nil string = "vm reference may not be nil" +) + // VmRef - virtual machine ref parts // map[type:qemu node:proxmox1-xx id:qemu/132 diskread:5.57424738e+08 disk:0 netin:5.9297450593e+10 mem:3.3235968e+09 uptime:1.4567097e+07 vmid:132 template:0 maxcpu:2 netout:6.053310416e+09 maxdisk:3.4359738368e+10 maxmem:8.592031744e+09 diskwrite:1.49663619584e+12 status:running cpu:0.00386980694947209 name:appt-app1-dev.xxx.xx] type VmRef struct { @@ -177,6 +181,9 @@ func (c *Client) GetVmList() (map[string]interface{}, error) { } func (c *Client) CheckVmRef(vmr *VmRef) (err error) { + if vmr == nil { + return errors.New(VmRef_Error_Nil) + } if vmr.node == "" || vmr.vmType == "" { _, err = c.GetVmInfo(vmr) } From 7c6d46ce75b54afe7dc0854460704df06573a423 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:46:12 +0000 Subject: [PATCH 176/191] refactor: nil check implemented by `CheckVmRef` --- proxmox/config_guest.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/proxmox/config_guest.go b/proxmox/config_guest.go index c969b1ef..78491f06 100644 --- a/proxmox/config_guest.go +++ b/proxmox/config_guest.go @@ -138,11 +138,7 @@ func ListGuests(client *Client) ([]GuestResource, error) { } func pendingGuestConfigFromApi(vmr *VmRef, client *Client) ([]interface{}, error) { - err := vmr.nilCheck() - if err != nil { - return nil, err - } - if err = client.CheckVmRef(vmr); err != nil { + if err := client.CheckVmRef(vmr); err != nil { return nil, err } return client.GetItemConfigInterfaceArray("/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/pending", "Guest", "PENDING CONFIG") From 11feae1f09a04483dcd94bcbadad72a4a3fc1550 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 19:59:15 +0000 Subject: [PATCH 177/191] feat: obtain features the guest has enabled Depending on the node, storage, config of the guest the clone, copy, snaspshot features might not be availible --- proxmox/config_guest.go | 71 ++++++++++++++++++++++++++++++++++++ proxmox/config_guest_test.go | 59 ++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/proxmox/config_guest.go b/proxmox/config_guest.go index 78491f06..ffc183a2 100644 --- a/proxmox/config_guest.go +++ b/proxmox/config_guest.go @@ -1,6 +1,7 @@ package proxmox import ( + "errors" "strconv" "strings" ) @@ -102,6 +103,40 @@ func (GuestResource) mapToStruct(params []interface{}) []GuestResource { return resources } +// Enum +type GuestFeature string + +const ( + GuestFeature_Clone GuestFeature = "clone" + GuestFeature_Copy GuestFeature = "copy" + GuestFeature_Snapshot GuestFeature = "snapshot" +) + +func (GuestFeature) Error() error { + return errors.New("value should be one of (" + string(GuestFeature_Clone) + " ," + string(GuestFeature_Copy) + " ," + string(GuestFeature_Snapshot) + ")") +} + +func (GuestFeature) mapToStruct(params map[string]interface{}) bool { + if value, isSet := params["hasFeature"]; isSet { + return Itob(int(value.(float64))) + } + return false +} + +func (feature GuestFeature) Validate() error { + switch feature { + case GuestFeature_Copy, GuestFeature_Clone, GuestFeature_Snapshot: + return nil + } + return GuestFeature("").Error() +} + +type GuestFeatures struct { + Clone bool `json:"clone"` + Copy bool `json:"copy"` + Snapshot bool `json:"snapshot"` +} + type GuestType string const ( @@ -109,6 +144,24 @@ const ( GuestQemu GuestType = "qemu" ) +// check if the guest has the specified feature. +func GuestHasFeature(vmr *VmRef, client *Client, feature GuestFeature) (bool, error) { + err := client.CheckVmRef(vmr) + if err != nil { + return false, err + } + return guestHasFeature(vmr, client, feature) +} + +func guestHasFeature(vmr *VmRef, client *Client, feature GuestFeature) (bool, error) { + var params map[string]interface{} + params, err := client.GetItemConfigMapStringInterface("/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/feature?feature=snapshot", "guest", "FEATURES") + if err != nil { + return false, err + } + return GuestFeature("").mapToStruct(params), nil +} + // Check if there are any pending changes that require a reboot to be applied. func GuestHasPendingChanges(vmr *VmRef, client *Client) (bool, error) { params, err := pendingGuestConfigFromApi(vmr, client) @@ -128,6 +181,24 @@ func GuestReboot(vmr *VmRef, client *Client) (err error) { return } +// List all features the guest has. +func ListGuestFeatures(vmr *VmRef, client *Client) (features GuestFeatures, err error) { + err = client.CheckVmRef(vmr) + if err != nil { + return + } + features.Clone, err = guestHasFeature(vmr, client, GuestFeature_Clone) + if err != nil { + return + } + features.Copy, err = guestHasFeature(vmr, client, GuestFeature_Copy) + if err != nil { + return + } + features.Snapshot, err = guestHasFeature(vmr, client, GuestFeature_Snapshot) + return +} + // List all guest the user has viewing rights for in the cluster func ListGuests(client *Client) ([]GuestResource, error) { list, err := client.GetResourceList("vm") diff --git a/proxmox/config_guest_test.go b/proxmox/config_guest_test.go index c2328d47..d22f5eec 100644 --- a/proxmox/config_guest_test.go +++ b/proxmox/config_guest_test.go @@ -237,3 +237,62 @@ func Test_GuestResource_mapToStruct(t *testing.T) { }) } } + +func Test_GuestFeature_mapToStruct(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + output bool + }{ + {name: "false", + input: map[string]interface{}{"hasFeature": float64(0)}, + output: false, + }, + {name: "not set", + input: map[string]interface{}{}, + output: false, + }, + {name: "true", + input: map[string]interface{}{"hasFeature": float64(1)}, + output: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.output, GuestFeature("").mapToStruct(test.input), test.name) + }) + } +} + +func Test_GuestFeature_Validate(t *testing.T) { + tests := []struct { + name string + input GuestFeature + err error + }{ + // Invalid + {name: "Invalid empty", + input: "", + err: GuestFeature("").Error(), + }, + {name: "Invalid not enum", + input: "invalid", + err: GuestFeature("").Error(), + }, + // Valid + {name: "Valid GuestFeature_Clone", + input: GuestFeature_Clone, + }, + {name: "Valid GuestFeature_Copy", + input: GuestFeature_Copy, + }, + {name: "Valid GuestFeature_Snapshot", + input: GuestFeature_Snapshot, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + require.Equal(t, test.err, test.input.Validate(), test.name) + }) + } +} From d5a6ce30b8c2ff636318d726aab2573ea65c618a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:02:24 +0000 Subject: [PATCH 178/191] refactor: nest config in guest command this is to allow for future guest commands --- cli/command/commands/commands.go | 1 + .../{get-guest.go => guest/get-guest-config.go} | 10 +++++----- cli/command/get/guest/get-guest.go | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) rename cli/command/get/{get-guest.go => guest/get-guest-config.go} (81%) create mode 100644 cli/command/get/guest/get-guest.go diff --git a/cli/command/commands/commands.go b/cli/command/commands/commands.go index f8798517..2b04aa1d 100644 --- a/cli/command/commands/commands.go +++ b/cli/command/commands/commands.go @@ -9,6 +9,7 @@ import ( _ "github.com/Telmate/proxmox-api-go/cli/command/delete" _ "github.com/Telmate/proxmox-api-go/cli/command/example" _ "github.com/Telmate/proxmox-api-go/cli/command/get" + _ "github.com/Telmate/proxmox-api-go/cli/command/get/guest" _ "github.com/Telmate/proxmox-api-go/cli/command/get/id" _ "github.com/Telmate/proxmox-api-go/cli/command/guest" _ "github.com/Telmate/proxmox-api-go/cli/command/guest/qemu" diff --git a/cli/command/get/get-guest.go b/cli/command/get/guest/get-guest-config.go similarity index 81% rename from cli/command/get/get-guest.go rename to cli/command/get/guest/get-guest-config.go index ffce1db7..0941785a 100644 --- a/cli/command/get/get-guest.go +++ b/cli/command/get/guest/get-guest-config.go @@ -1,4 +1,4 @@ -package get +package guest import ( "github.com/Telmate/proxmox-api-go/cli" @@ -6,8 +6,8 @@ import ( "github.com/spf13/cobra" ) -var get_guestCmd = &cobra.Command{ - Use: "guest GUESTID", +var configCmd = &cobra.Command{ + Use: "config GUESTID", Short: "Gets the configuration of the specified guest", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { @@ -29,11 +29,11 @@ var get_guestCmd = &cobra.Command{ if err != nil { return } - cli.PrintFormattedJson(GetCmd.OutOrStdout(), config) + cli.PrintFormattedJson(guestCmd.OutOrStdout(), config) return }, } func init() { - GetCmd.AddCommand(get_guestCmd) + guestCmd.AddCommand(configCmd) } diff --git a/cli/command/get/guest/get-guest.go b/cli/command/get/guest/get-guest.go new file mode 100644 index 00000000..81672e75 --- /dev/null +++ b/cli/command/get/guest/get-guest.go @@ -0,0 +1,15 @@ +package guest + +import ( + "github.com/Telmate/proxmox-api-go/cli/command/get" + "github.com/spf13/cobra" +) + +var guestCmd = &cobra.Command{ + Use: "guest", + Short: "Commands to get information of guests on Proxmox", +} + +func init() { + get.GetCmd.AddCommand(guestCmd) +} From ca58b91dcca44ff40c3ad92d8c91944b825b6d2c Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:03:17 +0000 Subject: [PATCH 179/191] feat: add command to get guests enabled features --- cli/command/get/guest/get-guest-feature.go | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 cli/command/get/guest/get-guest-feature.go diff --git a/cli/command/get/guest/get-guest-feature.go b/cli/command/get/guest/get-guest-feature.go new file mode 100644 index 00000000..d19b87e0 --- /dev/null +++ b/cli/command/get/guest/get-guest-feature.go @@ -0,0 +1,32 @@ +package guest + +import ( + "github.com/Telmate/proxmox-api-go/cli" + "github.com/Telmate/proxmox-api-go/proxmox" + "github.com/spf13/cobra" +) + +var featureCmd = &cobra.Command{ + Use: "feature GUESTID", + Short: "Gets the available features of the specified guest", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + id := cli.ValidateIntIDset(args, "GuestID") + vmr := proxmox.NewVmRef(id) + c := cli.NewClient() + err = c.CheckVmRef(vmr) + if err != nil { + return + } + features, err := proxmox.ListGuestFeatures(vmr, c) + if err != nil { + return + } + cli.PrintFormattedJson(guestCmd.OutOrStdout(), features) + return + }, +} + +func init() { + guestCmd.AddCommand(featureCmd) +} From daeb78f5a0180f4d4af02f68d735f11c7ffa90eb Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:07:15 +0000 Subject: [PATCH 180/191] feat: validate input is enum value --- proxmox/config_guest.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proxmox/config_guest.go b/proxmox/config_guest.go index ffc183a2..db25050c 100644 --- a/proxmox/config_guest.go +++ b/proxmox/config_guest.go @@ -146,7 +146,11 @@ const ( // check if the guest has the specified feature. func GuestHasFeature(vmr *VmRef, client *Client, feature GuestFeature) (bool, error) { - err := client.CheckVmRef(vmr) + err := feature.Validate() + if err != nil { + return false, err + } + err = client.CheckVmRef(vmr) if err != nil { return false, err } From e2dc5b8c766a39431d4ef207116c8f2a9885fc54 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 16 Jul 2023 16:40:18 +0000 Subject: [PATCH 181/191] feat: add type `SnapshotName` --- cli/command/create/create-snapshot.go | 2 +- cli/command/delete/delete-snapshot.go | 2 +- .../update/update-snapshotdescription.go | 2 +- proxmox/client.go | 2 +- proxmox/snapshot.go | 36 +++++++++++-------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cli/command/create/create-snapshot.go b/cli/command/create/create-snapshot.go index 510feeb1..e187fa68 100644 --- a/cli/command/create/create-snapshot.go +++ b/cli/command/create/create-snapshot.go @@ -18,7 +18,7 @@ var ( id := cli.ValidateIntIDset(args, "GuestID") snapName := cli.RequiredIDset(args, 1, "SnapshotName") config := proxmox.ConfigSnapshot{ - Name: snapName, + Name: proxmox.SnapshotName(snapName), Description: cli.OptionalIDset(args, 2), VmState: memory, } diff --git a/cli/command/delete/delete-snapshot.go b/cli/command/delete/delete-snapshot.go index 06538fab..7fd7e00b 100644 --- a/cli/command/delete/delete-snapshot.go +++ b/cli/command/delete/delete-snapshot.go @@ -14,7 +14,7 @@ var ( RunE: func(cmd *cobra.Command, args []string) (err error) { id := cli.ValidateIntIDset(args, "GuestID") snapName := cli.RequiredIDset(args, 1, "SnapshotName") - _, err = proxmox.DeleteSnapshot(cli.NewClient(), proxmox.NewVmRef(id), snapName) + _, err = proxmox.DeleteSnapshot(cli.NewClient(), proxmox.NewVmRef(id), proxmox.SnapshotName(snapName)) if err != nil { return } diff --git a/cli/command/update/update-snapshotdescription.go b/cli/command/update/update-snapshotdescription.go index 93775f51..adb400d7 100644 --- a/cli/command/update/update-snapshotdescription.go +++ b/cli/command/update/update-snapshotdescription.go @@ -14,7 +14,7 @@ var update_snapshotCmd = &cobra.Command{ id := cli.ValidateIntIDset(args, "GuestID") snapName := cli.RequiredIDset(args, 1, "SnapshotName") des := cli.OptionalIDset(args, 2) - err = proxmox.UpdateSnapshotDescription(cli.NewClient(), proxmox.NewVmRef(id), snapName, des) + err = proxmox.UpdateSnapshotDescription(cli.NewClient(), proxmox.NewVmRef(id), proxmox.SnapshotName(snapName), des) if err != nil { return } diff --git a/proxmox/client.go b/proxmox/client.go index 548c2c8f..f2c2a9bc 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -684,7 +684,7 @@ func (c *Client) CreateQemuSnapshot(vmr *VmRef, snapshotName string) (exitStatus // DEPRECATED superseded by DeleteSnapshot() func (c *Client) DeleteQemuSnapshot(vmr *VmRef, snapshotName string) (exitStatus string, err error) { - return DeleteSnapshot(c, vmr, snapshotName) + return DeleteSnapshot(c, vmr, SnapshotName(snapshotName)) } // DEPRECATED superseded by ListSnapshots() diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index c89e7c0d..20755010 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -7,9 +7,9 @@ import ( ) type ConfigSnapshot struct { - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - VmState bool `json:"ram,omitempty"` + Name SnapshotName `json:"name,omitempty"` + Description string `json:"description,omitempty"` + VmState bool `json:"ram,omitempty"` } func (config ConfigSnapshot) mapToApiValues() map[string]interface{} { @@ -45,20 +45,20 @@ func ListSnapshots(c *Client, vmr *VmRef) (rawSnapshots, error) { } // Can only be used to update the description of an already existing snapshot -func UpdateSnapshotDescription(c *Client, vmr *VmRef, snapshot, description string) (err error) { +func UpdateSnapshotDescription(c *Client, vmr *VmRef, snapshot SnapshotName, description string) (err error) { err = c.CheckVmRef(vmr) if err != nil { return } - return c.Put(map[string]interface{}{"description": description}, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/snapshot/"+snapshot+"/config") + return c.Put(map[string]interface{}{"description": description}, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/snapshot/"+string(snapshot)+"/config") } -func DeleteSnapshot(c *Client, vmr *VmRef, snapshot string) (exitStatus string, err error) { +func DeleteSnapshot(c *Client, vmr *VmRef, snapshot SnapshotName) (exitStatus string, err error) { err = c.CheckVmRef(vmr) if err != nil { return } - return c.DeleteWithTask("/nodes/" + vmr.node + "/" + vmr.vmType + "/" + strconv.Itoa(vmr.vmId) + "/snapshot/" + snapshot) + return c.DeleteWithTask("/nodes/" + vmr.node + "/" + vmr.vmType + "/" + strconv.Itoa(vmr.vmId) + "/snapshot/" + string(snapshot)) } func RollbackSnapshot(c *Client, vmr *VmRef, snapshot string) (exitStatus string, err error) { @@ -71,12 +71,12 @@ func RollbackSnapshot(c *Client, vmr *VmRef, snapshot string) (exitStatus string // Used for formatting the output when retrieving snapshots type Snapshot struct { - Name string `json:"name"` - SnapTime uint `json:"time,omitempty"` - Description string `json:"description,omitempty"` - VmState bool `json:"ram,omitempty"` - Children []*Snapshot `json:"children,omitempty"` - Parent string `json:"parent,omitempty"` + Name SnapshotName `json:"name"` + SnapTime uint `json:"time,omitempty"` + Description string `json:"description,omitempty"` + VmState bool `json:"ram,omitempty"` + Children []*Snapshot `json:"children,omitempty"` + Parent string `json:"parent,omitempty"` } // Formats the taskResponse as a list of snapshots @@ -88,7 +88,7 @@ func (raw rawSnapshots) FormatSnapshotsList() (list []*Snapshot) { list[i].Description = e.(map[string]interface{})["description"].(string) } if _, isSet := e.(map[string]interface{})["name"]; isSet { - list[i].Name = e.(map[string]interface{})["name"].(string) + list[i].Name = SnapshotName(e.(map[string]interface{})["name"].(string)) } if _, isSet := e.(map[string]interface{})["parent"]; isSet { list[i].Parent = e.(map[string]interface{})["parent"].(string) @@ -108,7 +108,7 @@ func (raw rawSnapshots) FormatSnapshotsTree() (tree []*Snapshot) { list := raw.FormatSnapshotsList() for _, e := range list { for _, ee := range list { - if e.Parent == ee.Name { + if e.Parent == string(ee.Name) { ee.Children = append(ee.Children, e) break } @@ -122,3 +122,9 @@ func (raw rawSnapshots) FormatSnapshotsTree() (tree []*Snapshot) { } return } + +// Minimum length of 3 characters +// Maximum length of 40 characters +// First character must be a letter +// Must only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ +type SnapshotName string From 4b6250eabb0f6984e16b16b225682e7fffae3b37 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 16 Jul 2023 16:44:19 +0000 Subject: [PATCH 182/191] feat: add `SnapshotName.Validate()` --- proxmox/snapshot.go | 34 +++++ proxmox/snapshot_test.go | 37 +++++ .../test_data_snapshot/type_SnapshotName.go | 131 ++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 test/data/test_data_snapshot/type_SnapshotName.go diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index 20755010..139950be 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -3,7 +3,9 @@ package proxmox import ( "encoding/json" "fmt" + "regexp" "strconv" + "unicode" ) type ConfigSnapshot struct { @@ -50,6 +52,10 @@ func UpdateSnapshotDescription(c *Client, vmr *VmRef, snapshot SnapshotName, des if err != nil { return } + err = snapshot.Validate() + if err != nil { + return + } return c.Put(map[string]interface{}{"description": description}, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/snapshot/"+string(snapshot)+"/config") } @@ -58,6 +64,10 @@ func DeleteSnapshot(c *Client, vmr *VmRef, snapshot SnapshotName) (exitStatus st if err != nil { return } + err = snapshot.Validate() + if err != nil { + return + } return c.DeleteWithTask("/nodes/" + vmr.node + "/" + vmr.vmType + "/" + strconv.Itoa(vmr.vmId) + "/snapshot/" + string(snapshot)) } @@ -128,3 +138,27 @@ func (raw rawSnapshots) FormatSnapshotsTree() (tree []*Snapshot) { // First character must be a letter // Must only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ type SnapshotName string + +const ( + SnapshotName_Error_IllegalCharacters string = "SnapshotName must only contain the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" + SnapshotName_Error_MaxLength string = "SnapshotName must be at most 40 characters long" + SnapshotName_Error_MinLength string = "SnapshotName must be at least 3 characters long" + SnapshotName_Error_StartNoLetter string = "SnapshotName must start with a letter" +) + +func (name SnapshotName) Validate() error { + regex, _ := regexp.Compile(`^([a-zA-Z])([a-z]|[A-Z]|[0-9]|_|-){2,39}$`) + if !regex.Match([]byte(name)) { + if len(name) < 3 { + return fmt.Errorf(SnapshotName_Error_MinLength) + } + if len(name) > 40 { + return fmt.Errorf(SnapshotName_Error_MaxLength) + } + if !unicode.IsLetter(rune(name[0])) { + return fmt.Errorf(SnapshotName_Error_StartNoLetter) + } + return fmt.Errorf(SnapshotName_Error_IllegalCharacters) + } + return nil +} diff --git a/proxmox/snapshot_test.go b/proxmox/snapshot_test.go index cd640218..3f736aa9 100644 --- a/proxmox/snapshot_test.go +++ b/proxmox/snapshot_test.go @@ -2,8 +2,10 @@ package proxmox import ( "encoding/json" + "errors" "testing" + "github.com/Telmate/proxmox-api-go/test/data/test_data_snapshot" "github.com/stretchr/testify/require" ) @@ -204,3 +206,38 @@ func test_FormatSnapshotsList_Output() []string { "name":"bba","time":1666362071,"parent":"bb"},{ "name":"bbb","time":1666362062,"parent":"bb"}]`} } + +func Test_SnapshotName_Validate(t *testing.T) { + tests := []struct { + name string + input []string + err error + }{ + // Valid + {name: "Valid", input: test_data_snapshot.SnapshotName_Legal()}, + // Invalid + {name: "Invalid SnapshotName_Error_MinLength", + input: []string{"", test_data_snapshot.SnapshotName_Min_Illegal()}, + err: errors.New(SnapshotName_Error_MinLength), + }, + {name: "Invalid SnapshotName_Error_MaxLength", + input: []string{test_data_snapshot.SnapshotName_Max_Illegal()}, + err: errors.New(SnapshotName_Error_MaxLength), + }, + {name: "Invalid SnapshotName_Error_StartNoLetter", + input: test_data_snapshot.SnapshotName_Start_Illegal(), + err: errors.New(SnapshotName_Error_StartNoLetter), + }, + {name: "Invalid SnapshotName_Error_StartNoLetter", + input: test_data_snapshot.SnapshotName_Character_Illegal(), + err: errors.New(SnapshotName_Error_IllegalCharacters), + }, + } + for _, test := range tests { + for _, snapshot := range test.input { + t.Run(test.name+" :"+snapshot, func(*testing.T) { + require.Equal(t, SnapshotName(snapshot).Validate(), test.err, test.name+" :"+snapshot) + }) + } + } +} diff --git a/test/data/test_data_snapshot/type_SnapshotName.go b/test/data/test_data_snapshot/type_SnapshotName.go new file mode 100644 index 00000000..a08a49ec --- /dev/null +++ b/test/data/test_data_snapshot/type_SnapshotName.go @@ -0,0 +1,131 @@ +package test_data_snapshot + +// illegal character +func SnapshotName_Character_Illegal() []string { + return []string{ + "aBc123!4567890_-", + "Qwer@ty-1234_ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "x1y2#z3_4-5-6-7-8-9", + "HelloWo$rld_2023", + "Ab1_%cd2_ef3-gh4-ij5", + "a-_-^_-_-_-_-_-_-_-_-_-", + "snaps&hotName_2433242", + "A1_B2-*C3_D4-E5_F6", + "Xyz-123(_456_789-0", + "Test_Cas)e-123_456_789_0", + "a_1+", + "B-c_=2-D", + "E3_f4-G5_:H6-I7", + "JKL_MNO_PQ;R-STU_VWX_YZ0", + "aBgnhfjkfgd'ihfghudsfgio", + `Cdsdjfidshfu"isdghfsgffghdsufsdhfgdsfuah`, + "Ef-`gh", + "Ij-k~l-mn", + "Op-qr-st-u-vw-xy-z0-12-34-56-[78-90", + "Abcd_1234-EFGH_]5678-IJKL_9012", + "M-n-Op-qR-sT-uV{-wX-yZ", + "a_b-c_d_e-f_g_h_}i_j_k_l_m_n-o-p-q-r-s-t", + "Aa1_Bb2-C,c3_Dd4-Ee5_Ff6-Gg7_Hh8-Ii9", + "JjKkLl-MmNnOo.PpQqRrSsTtUuVvWwXxYyZz01", + "A->1", + "B-2<_C-3", + "D-4_?E-5-F-6", + "G-7-H/-8-I-9", + `J-0_K-\1-L-2-M-3-N-4-O-5-P-6-Q-7-R-8-S-9`, + "T-0_U-1-|V-2-W-3-X-4-Y-5-Z-6-7-8-9-0", + "a2😀", + } +} + +// 40 valid characters +func SnapshotName_Max_Legal() string { + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN" +} + +// 41 invalid characters +func SnapshotName_Max_Illegal() string { + return SnapshotName_Max_Legal() + "A" +} + +// 3 valid characters +func SnapshotName_Min_Legal() string { + return SnapshotName_Min_Illegal() + "c" +} + +// 2 invalid characters +func SnapshotName_Min_Illegal() string { + return "ab" +} + +// legal starting character +func SnapshotName_Start_Legal() string { + return "abc" +} + +// illegal starting character +func SnapshotName_Start_Illegal() []string { + return []string{ + "_" + SnapshotName_Start_Legal(), + "-" + SnapshotName_Start_Legal(), + "0" + SnapshotName_Start_Legal(), + "5" + SnapshotName_Start_Legal(), + } +} + +func SnapshotName_Legal() []string { + return []string{ + "aBc1234567890_-", + "Qwerty-1234_ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "x1y2z3_4-5-6-7-8-9", + "HelloWorld_2023", + "Ab1_cd2_ef3-gh4-ij5", + "a-_-_-_-_-_-_-_-_-_-_-", + "snapshotName_2433242", + "A1_B2-C3_D4-E5_F6", + "Xyz-123_456_789-0", + "Test_Case-123_456_789_0", + "a_1", + "B-c_2-D", + "E3_f4-G5_H6-I7", + "JKL_MNO_PQR-STU_VWX_YZ0", + "aBgnhfjkfgdihfghudsfgio", + "Cdsdjfidshfuisdghfsgffghdsufsdhfgdsfuahs", + "Ef-gh", + "Ij-kl-mn", + "Op-qr-st-u-vw-xy-z0-12-34-56-78-90", + "Abcd_1234-EFGH_5678-IJKL_9012", + "M-n-Op-qR-sT-uV-wX-yZ", + "a_b-c_d_e-f_g_h_i_j_k_l_m_n-o-p-q-r-s-t-", + "Aa1_Bb2-Cc3_Dd4-Ee5_Ff6-Gg7_Hh8-Ii9", + "JjKkLl-MmNnOoPpQqRrSsTtUuVvWwXxYyZz01", + "A-1", + "B-2_C-3", + "D-4_E-5-F-6", + "G-7-H-8-I-9", + "J-0_K-1-L-2-M-3-N-4-O-5-P-6-Q-7-R-8-S-9", + "T-0_U-1-V-2-W-3-X-4-Y-5-Z-6-7-8-9-0", + "a2B", + "c4D", + "e6F-g8H-i0J", + "k2L-m4N-o6P-q8R-s0T", + "u2V-w4X-y6Z-01-23-45-67-89-0", + "Abc_1234-Def_5678-Ghi_9012-Jkl_3456-Mno_", + "Pqr_2345-Stu_6789-Vwx_0123-Yz0_4567", + "a-B", + "c-D_e-F", + "g-H_i-J-k-L", + "m-N-o-P_q-R-s-T-u-V-w-X-y-Z-0", + "A_1b2-C3d4_E5f6-G7h8_I9j0-K1l2-M3n4", + "O5p6-Q7r8-S9t0-U1v2-W3x4-Y5z6-01", + "A2b3-C4d5-E6f7-G8h9-I0j1-K2l3-M4n5-O6", + "P7q8-R9s0-T1u2-V3w4-X5y6-Z7-89-01-23-45-", + "Ab_12-cD_34-eF_56-gH_78-iJ_90-kL_12-mN_3", + "O5p6-Q7r8-S9t0-U1v2-W3x4-Y5z6-01-23-45", + "A7b8-C9d0-E1f2-G3h4-I5j6-K7l8-M9n0-O1p2-", + "S5t6-U7v8-W9x0-Y1z2-34-56-78-90-12-34-56", + "Ab1C_d2E-F3G_h4I-J5k6L-m7N-o8P-q9R-s0T-u", + SnapshotName_Max_Legal(), + SnapshotName_Min_Legal(), + SnapshotName_Start_Legal(), + } +} From dda7c40dc5ff402f4dd50dfb55de03d6c6ac3bf2 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 16 Jul 2023 16:46:48 +0000 Subject: [PATCH 183/191] feat: add `ConfigSnapshot.Validate()` --- proxmox/snapshot.go | 10 +++++++++- proxmox/snapshot_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index 139950be..83b5c317 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -23,11 +23,15 @@ func (config ConfigSnapshot) mapToApiValues() map[string]interface{} { } func (config ConfigSnapshot) CreateSnapshot(c *Client, vmr *VmRef) (err error) { - params := config.mapToApiValues() err = c.CheckVmRef(vmr) if err != nil { return } + err = config.Validate() + if err != nil { + return + } + params := config.mapToApiValues() _, err = c.PostWithTask(params, "/nodes/"+vmr.node+"/"+vmr.vmType+"/"+strconv.Itoa(vmr.vmId)+"/snapshot/") if err != nil { params, _ := json.Marshal(¶ms) @@ -36,6 +40,10 @@ func (config ConfigSnapshot) CreateSnapshot(c *Client, vmr *VmRef) (err error) { return } +func (config ConfigSnapshot) Validate() error { + return config.Name.Validate() +} + type rawSnapshots []interface{} func ListSnapshots(c *Client, vmr *VmRef) (rawSnapshots, error) { diff --git a/proxmox/snapshot_test.go b/proxmox/snapshot_test.go index 3f736aa9..9bdc37ea 100644 --- a/proxmox/snapshot_test.go +++ b/proxmox/snapshot_test.go @@ -9,6 +9,33 @@ import ( "github.com/stretchr/testify/require" ) +func Test_ConfigSnapshot_Validate(t *testing.T) { + tests := []struct { + name string + input ConfigSnapshot + err bool + }{ + // Valid + {name: "Valid ConfigSnapshot", + input: ConfigSnapshot{Name: SnapshotName(test_data_snapshot.SnapshotName_Max_Legal())}, + }, + // Invalid + {name: "Invalid ConfigSnapshot", + input: ConfigSnapshot{Name: SnapshotName(test_data_snapshot.SnapshotName_Max_Illegal())}, + err: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(*testing.T) { + if test.err { + require.Error(t, test.input.Validate(), test.name) + } else { + require.NoError(t, test.input.Validate(), test.name) + } + }) + } +} + // Test the formatting logic to build the tree of snapshots func Test_FormatSnapshotsTree(t *testing.T) { input := test_FormatSnapshots_Input() From 4ce3993d5cc03d374237c19276471e97c42f13b3 Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Sun, 16 Jul 2023 16:50:03 +0000 Subject: [PATCH 184/191] Add TODO --- proxmox/snapshot.go | 1 + proxmox/snapshot_test.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index 83b5c317..c570e0f4 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -14,6 +14,7 @@ type ConfigSnapshot struct { VmState bool `json:"ram,omitempty"` } +// TODO write tests for this func (config ConfigSnapshot) mapToApiValues() map[string]interface{} { return map[string]interface{}{ "snapname": config.Name, diff --git a/proxmox/snapshot_test.go b/proxmox/snapshot_test.go index 9bdc37ea..24c042a9 100644 --- a/proxmox/snapshot_test.go +++ b/proxmox/snapshot_test.go @@ -36,6 +36,7 @@ func Test_ConfigSnapshot_Validate(t *testing.T) { } } +// TODO rename this test // Test the formatting logic to build the tree of snapshots func Test_FormatSnapshotsTree(t *testing.T) { input := test_FormatSnapshots_Input() @@ -46,6 +47,7 @@ func Test_FormatSnapshotsTree(t *testing.T) { } } +// TODO rename this test // Test the formatting logic to build the list of snapshots func Test_FormatSnapshotsList(t *testing.T) { input := test_FormatSnapshots_Input() From 9426f5ac84211f98db554c5447a491494b1bcf2a Mon Sep 17 00:00:00 2001 From: Tinyblargon <76069640+Tinyblargon@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:42:13 +0000 Subject: [PATCH 185/191] fix: `Parent` should be of type `SnapshotName` --- proxmox/snapshot.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxmox/snapshot.go b/proxmox/snapshot.go index c570e0f4..35243947 100644 --- a/proxmox/snapshot.go +++ b/proxmox/snapshot.go @@ -95,7 +95,7 @@ type Snapshot struct { Description string `json:"description,omitempty"` VmState bool `json:"ram,omitempty"` Children []*Snapshot `json:"children,omitempty"` - Parent string `json:"parent,omitempty"` + Parent SnapshotName `json:"parent,omitempty"` } // Formats the taskResponse as a list of snapshots @@ -110,7 +110,7 @@ func (raw rawSnapshots) FormatSnapshotsList() (list []*Snapshot) { list[i].Name = SnapshotName(e.(map[string]interface{})["name"].(string)) } if _, isSet := e.(map[string]interface{})["parent"]; isSet { - list[i].Parent = e.(map[string]interface{})["parent"].(string) + list[i].Parent = SnapshotName(e.(map[string]interface{})["parent"].(string)) } if _, isSet := e.(map[string]interface{})["snaptime"]; isSet { list[i].SnapTime = uint(e.(map[string]interface{})["snaptime"].(float64)) @@ -127,7 +127,7 @@ func (raw rawSnapshots) FormatSnapshotsTree() (tree []*Snapshot) { list := raw.FormatSnapshotsList() for _, e := range list { for _, ee := range list { - if e.Parent == string(ee.Name) { + if e.Parent == ee.Name { ee.Children = append(ee.Children, e) break } From 394604b9e3ed815bc2415c6975ba98771b3cd36d Mon Sep 17 00:00:00 2001 From: Mice7R Date: Mon, 21 Aug 2023 20:25:04 +0200 Subject: [PATCH 186/191] Fix DiskSize regex to accept decimals --- proxmox/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmox/util.go b/proxmox/util.go index 34eec5fe..6779bf77 100644 --- a/proxmox/util.go +++ b/proxmox/util.go @@ -121,7 +121,7 @@ func DiskSizeGB(dcSize interface{}) float64 { switch dcSize := dcSize.(type) { case string: diskString := strings.ToUpper(dcSize) - re := regexp.MustCompile("([0-9]+)([A-Z]*)") + re := regexp.MustCompile("([0-9]+(?:\.[0-9]+)?)([TGMK]B?)?") diskArray := re.FindStringSubmatch(diskString) diskSize, _ = strconv.ParseFloat(diskArray[1], 64) From 6f3ba462fa9cb437321197f2ecd9ab524ef863a4 Mon Sep 17 00:00:00 2001 From: Rafael Rivera Date: Thu, 2 Nov 2023 23:42:14 -0700 Subject: [PATCH 187/191] Add efidisk support to qemu config --- proxmox/config_qemu.go | 28 ++++++++++++++++++++++++++++ proxmox/config_qemu_test.go | 11 +++++++++++ 2 files changed, 39 insertions(+) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index aeedcd42..df41aa52 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -790,6 +790,15 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error } } + // efidisk + if efidisk, isSet := params["efidisk0"].(string); isSet { + efiDiskConfMap := ParsePMConf(efidisk, "volume") + storageName, fileName := ParseSubConf(efiDiskConfMap["volume"].(string), ":") + efiDiskConfMap["storage"] = storageName + efiDiskConfMap["file"] = fileName + config.EFIDisk = efiDiskConfMap + } + return &config, nil } @@ -1208,7 +1217,26 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e if err != nil { return } + + if config.EFIDisk != nil { + storageContent, err := client.GetStorageContent(vmr, config.EFIDisk["storage"].(string)) + if err != nil { + log.Fatal(err) + return nil, err + } + + contents := storageContent["data"].([]interface{}) + for content := range contents { + storageContentMap := contents[content].(map[string]interface{}) + if storageContentMap["volid"] == config.EFIDisk["volume"].(string) { + config.EFIDisk["format"] = storageContentMap["format"].(string) + break + } + } + } + config.defaults() + // HAstate is return by the api for a vm resource type but not the HAgroup err = client.ReadVMHA(vmr) if err == nil { diff --git a/proxmox/config_qemu_test.go b/proxmox/config_qemu_test.go index 68f7a8f3..5ac514f2 100644 --- a/proxmox/config_qemu_test.go +++ b/proxmox/config_qemu_test.go @@ -4371,6 +4371,17 @@ func Test_ConfigQemu_mapToStruct(t *testing.T) { }}}}, }, }, + // EFI + {name: "EFI Disk", + input: map[string]interface{}{"efidisk0": "local-lvm:vm-1000-disk-0,efitype=2m,size=4M"}, + output: &ConfigQemu{EFIDisk: map[string]interface{}{ + "efitype": "2m", + "size": "4M", + "storage": "local-lvm", + "file": "vm-1000-disk-0", + "volume": "local-lvm:vm-1000-disk-0", + }}, + }, } for _, test := range tests { t.Run(test.name, func(*testing.T) { From a957835da721d7217d38458e82d747abfea9f5fc Mon Sep 17 00:00:00 2001 From: Lucian Alexandru Date: Tue, 7 Nov 2023 09:28:52 +0100 Subject: [PATCH 188/191] Feature: add RebootVM capability --- proxmox/client.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proxmox/client.go b/proxmox/client.go index 548c2c8f..be4e7be7 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -501,6 +501,10 @@ func (c *Client) ResetVm(vmr *VmRef) (exitStatus string, err error) { return c.StatusChangeVm(vmr, nil, "reset") } +func (c *Client) RebootVm(vmr *VmRef) (exitStatus string, err error) { + return c.StatusChangeVm(vmr, nil, "reboot") +} + func (c *Client) PauseVm(vmr *VmRef) (exitStatus string, err error) { return c.StatusChangeVm(vmr, nil, "suspend") } @@ -765,7 +769,7 @@ func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitSt func (c *Client) ResizeQemuDiskRaw(vmr *VmRef, disk string, size string) (exitStatus interface{}, err error) { // PUT //disk:virtio0 - //size:+2G + // size:+2G if disk == "" { disk = "virtio0" } From d062c3c600ea0abfe962c2e3fa831a523cdc672b Mon Sep 17 00:00:00 2001 From: FredrickB <8116958+FredrickB@users.noreply.github.com> Date: Tue, 7 Nov 2023 19:34:10 +0100 Subject: [PATCH 189/191] feat: add support for unlinking disks from VM Client can now perform unlink operation for a given VM and a set of disks. This is useful in situations where it's important that the VM remains while allowing the disks to correctly be unlinked (detached) and consequently deleted. --- README.md | 2 ++ main.go | 28 ++++++++++++++++++++++++++++ proxmox/client.go | 19 +++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/README.md b/README.md index 7093cdce..d8b200d3 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ export PM_HTTP_HEADERS=Key,Value,Key1,Value1 (only if required) ./proxmox-api-go node shutdown proxmox-node-name +./proxmox-api-go unlink 123 proxmox-node-name "virtio1,virtio2,virtioN" [false|true] + ``` ## Proxy server support diff --git a/main.go b/main.go index 1c0dd2a4..d6fafc25 100644 --- a/main.go +++ b/main.go @@ -921,6 +921,34 @@ func main() { failError(err) fmt.Println(string(dnsList)) + case "unlink": + if len(flag.Args()) < 4 { + failError(fmt.Errorf("error: invoke with ]")) + } + + vmIdUnparsed := flag.Args()[1] + node := flag.Args()[2] + vmId, err := strconv.Atoi(vmIdUnparsed) + if err != nil { + failError(fmt.Errorf("Failed to convert vmId: %s to a string, error: %+v", vmIdUnparsed, err)) + } + + disks := flag.Args()[3] + forceRemoval := false + if len(flag.Args()) > 4 { + forceRemovalUnparsed := flag.Args()[4] + forceRemoval, err = strconv.ParseBool(forceRemovalUnparsed) + if err != nil { + failError(fmt.Errorf("Failed to convert : %s to a bool, error: %+v", forceRemovalUnparsed, err)) + } + } + + exitStatus, err := c.Unlink(node, vmId, disks, forceRemoval) + if err != nil { + failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus)) + } + log.Printf("Unlinked disks: %s from vmId: %d. Disks removed: %t", disks, vmId, forceRemoval) + default: fmt.Printf("unknown action, try start|stop vmid\n") } diff --git a/proxmox/client.go b/proxmox/client.go index 548c2c8f..195ace61 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -842,6 +842,25 @@ func (c *Client) MoveQemuDiskToVM(vmrSource *VmRef, disk string, vmrTarget *VmRe return } +// Unlink - Unlink (detach) a set of disks from a VM. +// Reference: https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node}/qemu/{vmid}/unlink +func (c *Client) Unlink(node string, vmId int, diskIds string, forceRemoval bool) (exitStatus string, err error) { + url := fmt.Sprintf("/nodes/%s/qemu/%d/unlink", node, vmId) + data := ParamsToBody(map[string]interface{}{ + "idlist": diskIds, + "force": forceRemoval, + }) + resp, err := c.session.Put(url, nil, nil, &data) + if err != nil { + return c.HandleTaskError(resp), err + } + json, err := ResponseJSON(resp) + if err != nil { + return "", err + } + return c.WaitForCompletion(json) +} + // GetNextID - Get next free VMID func (c *Client) GetNextID(currentID int) (nextID int, err error) { var data map[string]interface{} From 39376bf954183a2ee6aa4c1e788307459435ae12 Mon Sep 17 00:00:00 2001 From: Sabuhi Gurbani <51547928+sabuhigr@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:10:53 +0400 Subject: [PATCH 190/191] Added Getting vm by id to client There is a method for getting VmRefbyName, but by Id was not exist before.Thats solution for others, who need. --- proxmox/client.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/proxmox/client.go b/proxmox/client.go index 548c2c8f..68c0e86a 100644 --- a/proxmox/client.go +++ b/proxmox/client.go @@ -244,6 +244,35 @@ func (c *Client) GetVmRefsByName(vmName string) (vmrs []*VmRef, err error) { } } +func (c *Client) GetVmRefById(vmId int) (vmr *VmRef, err error) { + var exist bool = false + vms, err := c.GetResourceList(resourceListGuest) + if err != nil { + return + } + for vmii := range vms { + vm := vms[vmii].(map[string]interface{}) + if int(vm["vmid"].(float64)) != 0 && int(vm["vmid"].(float64)) == vmId { + vmr = NewVmRef(int(vm["vmid"].(float64))) + vmr.node = vm["node"].(string) + vmr.vmType = vm["type"].(string) + vmr.pool = "" + if vm["pool"] != nil { + vmr.pool = vm["pool"].(string) + } + if vm["hastate"] != nil { + vmr.haState = vm["hastate"].(string) + } + return + } + } + if !exist { + return nil, fmt.Errorf("vm 'id-%d' not found", vmId) + } else { + return + } +} + func (c *Client) GetVmState(vmr *VmRef) (vmState map[string]interface{}, err error) { err = c.CheckVmRef(vmr) if err != nil { From 0d37a47d49a45a440a5ba272d18ff1cc56a8a142 Mon Sep 17 00:00:00 2001 From: thorntonmc Date: Thu, 30 Nov 2023 19:34:53 +0300 Subject: [PATCH 191/191] type check memory --- proxmox/config_qemu.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/proxmox/config_qemu.go b/proxmox/config_qemu.go index aeedcd42..914e51b1 100644 --- a/proxmox/config_qemu.go +++ b/proxmox/config_qemu.go @@ -517,7 +517,16 @@ func (ConfigQemu) mapToStruct(params map[string]interface{}) (*ConfigQemu, error config.Hookscript = params["hookscript"].(string) } if _, isSet := params["memory"]; isSet { - config.Memory = int(params["memory"].(float64)) + switch params["memory"].(type) { + case float64: + config.Memory = int(params["memory"].(float64)) + case string: + mem, err := strconv.ParseFloat(params["memory"].(string), 64) + if err != nil { + return nil, err + } + config.Memory = int(mem) + } } if _, isSet := params["name"]; isSet { config.Name = params["name"].(string)