diff --git a/builder/proxmox/config.go b/builder/proxmox/config.go index f1a86bebf..07512ca41 100644 --- a/builder/proxmox/config.go +++ b/builder/proxmox/config.go @@ -86,6 +86,7 @@ type diskConfig struct { Size string `mapstructure:"disk_size"` CacheMode string `mapstructure:"cache_mode"` DiskFormat string `mapstructure:"format"` + IOThread bool `mapstructure:"io_thread"` } type vgaConfig struct { Type string `mapstructure:"type"` @@ -189,6 +190,17 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { log.Printf("Disk %d cache mode not set, using default 'none'", idx) c.Disks[idx].CacheMode = "none" } + if c.Disks[idx].IOThread { + // io thread is only supported by virtio-scsi-single controller + if c.SCSIController != "virtio-scsi-single" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("io thread option requires virtio-scsi-single controller")) + } else { + // ... and only for virtio and scsi disks + if !(c.Disks[idx].Type == "scsi" || c.Disks[idx].Type == "virtio") { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("io thread option requires scsi or a virtio disk")) + } + } + } // For any storage pool types which aren't in rxStorageTypes in proxmox-api/proxmox/config_qemu.go:890 // (currently zfspool|lvm|rbd|cephfs), the format parameter is mandatory. Make sure this is still up to date // when updating the vendored code! diff --git a/builder/proxmox/config.hcl2spec.go b/builder/proxmox/config.hcl2spec.go index b53b1239e..53055378b 100644 --- a/builder/proxmox/config.hcl2spec.go +++ b/builder/proxmox/config.hcl2spec.go @@ -230,6 +230,7 @@ type FlatdiskConfig struct { Size *string `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` CacheMode *string `mapstructure:"cache_mode" cty:"cache_mode" hcl:"cache_mode"` DiskFormat *string `mapstructure:"format" cty:"format" hcl:"format"` + IOThread *bool `mapstructure:"io_thread" cty:"io_thread" hcl:"io_thread"` } // FlatMapstructure returns a new FlatdiskConfig. @@ -250,6 +251,7 @@ func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec { "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.String, Required: false}, "cache_mode": &hcldec.AttrSpec{Name: "cache_mode", Type: cty.String, Required: false}, "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, + "io_thread": &hcldec.AttrSpec{Name: "io_thread", Type: cty.Bool, Required: false}, } return s } diff --git a/builder/proxmox/config_test.go b/builder/proxmox/config_test.go index e17d2e82f..39019b85e 100644 --- a/builder/proxmox/config_test.go +++ b/builder/proxmox/config_test.go @@ -208,3 +208,52 @@ func TestPacketQueueSupportForNetworkAdapters(t *testing.T) { } } } + +func TestHardDiskControllerIOThreadSupport(t *testing.T) { + drivertests := []struct { + expectedToFail bool + controller string + disk_type string + }{ + // io thread is only supported by virtio-scsi-single controller + // and only for virtio and scsi disks + {expectedToFail: false, controller: "virtio-scsi-single", disk_type: "scsi"}, + {expectedToFail: false, controller: "virtio-scsi-single", disk_type: "virtio"}, + {expectedToFail: true, controller: "virtio-scsi-single", disk_type: "sata"}, + {expectedToFail: true, controller: "lsi", disk_type: "scsi"}, + {expectedToFail: true, controller: "lsi53c810", disk_type: "virtio"}, + } + + for _, tt := range drivertests { + nic := make(map[string]interface{}) + nic["bridge"] = "vmbr0" + + nics := make([]map[string]interface{}, 0) + nics = append(nics, nic) + + disk := make(map[string]interface{}) + disk["type"] = tt.disk_type + disk["io_thread"] = true + disk["storage_pool"] = "local-lvm" + disk["storage_pool_type"] = "lvm" + + disks := make([]map[string]interface{}, 0) + disks = append(disks, disk) + + cfg := mandatoryConfig(t) + cfg["network_adapters"] = nics + cfg["disks"] = disks + cfg["scsi_controller"] = tt.controller + + var c Config + _, err := c.Prepare(cfg) + + if tt.expectedToFail == true && err == nil { + t.Error("expected config preparation to fail, but no error occured") + } + + if tt.expectedToFail == false && err != nil { + t.Errorf("expected config preparation to succeed, but %s", err.Error()) + } + } +} diff --git a/builder/proxmox/step_start_vm.go b/builder/proxmox/step_start_vm.go index c128fe44c..23ccfbf80 100644 --- a/builder/proxmox/step_start_vm.go +++ b/builder/proxmox/step_start_vm.go @@ -142,6 +142,10 @@ func generateProxmoxDisks(disks []diskConfig) proxmox.QemuDevices { setDeviceParamIfDefined(devs[idx], "storage_type", disks[idx].StoragePoolType) setDeviceParamIfDefined(devs[idx], "cache", disks[idx].CacheMode) setDeviceParamIfDefined(devs[idx], "format", disks[idx].DiskFormat) + + if devs[idx]["type"] == "scsi" || devs[idx]["type"] == "virtio" { + setDeviceParamIfDefined(devs[idx], "iothread", strconv.FormatBool(disks[idx].IOThread)) + } } return devs } diff --git a/website/pages/docs/builders/proxmox.mdx b/website/pages/docs/builders/proxmox.mdx index acef9881e..1e3525bb4 100644 --- a/website/pages/docs/builders/proxmox.mdx +++ b/website/pages/docs/builders/proxmox.mdx @@ -185,6 +185,11 @@ builder. `raw`, `cow`, `qcow`, `qed`, `qcow2`, `vmdk` or `cloop`. Defaults to `raw`. + - `io_thread` (bool) - Create one I/O thread per storage controller, rather + than a single thread for all I/O. This can increase performance when + multiple disks are used. Requires `virtio-scsi-single` controller and a + `scsi` or `virtio` disk. Defaults to `false`. + - `template_name` (string) - Name of the template. Defaults to the generated name used during creation.