From 7ed870948374b83416c013fc2513e3dbbcdaf851 Mon Sep 17 00:00:00 2001 From: Roman Tomjak <6570684+romantomjak@users.noreply.github.com> Date: Wed, 15 Jul 2020 23:07:02 +0100 Subject: [PATCH] add option to configure network adapter multiqueue support --- builder/proxmox/config.go | 14 +++++--- builder/proxmox/config.hcl2spec.go | 22 ++++++------ builder/proxmox/config_test.go | 56 ++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/builder/proxmox/config.go b/builder/proxmox/config.go index 22cb6786d..f97ec090a 100644 --- a/builder/proxmox/config.go +++ b/builder/proxmox/config.go @@ -67,11 +67,12 @@ type Config struct { } type nicConfig struct { - Model string `mapstructure:"model"` - MACAddress string `mapstructure:"mac_address"` - Bridge string `mapstructure:"bridge"` - VLANTag string `mapstructure:"vlan_tag"` - Firewall bool `mapstructure:"firewall"` + Model string `mapstructure:"model"` + PacketQueues int `mapstructure:"packet_queues"` + MACAddress string `mapstructure:"mac_address"` + Bridge string `mapstructure:"bridge"` + VLANTag string `mapstructure:"vlan_tag"` + Firewall bool `mapstructure:"firewall"` } type diskConfig struct { Type string `mapstructure:"type"` @@ -233,6 +234,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { if c.NICs[idx].Bridge == "" { errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("network_adapters[%d].bridge must be specified", idx))) } + if c.NICs[idx].Model != "virtio" && c.NICs[idx].PacketQueues > 0 { + errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("network_adapters[%d].packet_queues can only be set for 'virtio' driver", idx))) + } } for idx := range c.Disks { if c.Disks[idx].StoragePool == "" { diff --git a/builder/proxmox/config.hcl2spec.go b/builder/proxmox/config.hcl2spec.go index 73a70b6a1..fe0e09c34 100644 --- a/builder/proxmox/config.hcl2spec.go +++ b/builder/proxmox/config.hcl2spec.go @@ -247,11 +247,12 @@ func (*FlatdiskConfig) HCL2Spec() map[string]hcldec.Spec { // FlatnicConfig is an auto-generated flat version of nicConfig. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatnicConfig struct { - Model *string `mapstructure:"model" cty:"model" hcl:"model"` - MACAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` - Bridge *string `mapstructure:"bridge" cty:"bridge" hcl:"bridge"` - VLANTag *string `mapstructure:"vlan_tag" cty:"vlan_tag" hcl:"vlan_tag"` - Firewall *bool `mapstructure:"firewall" cty:"firewall" hcl:"firewall"` + Model *string `mapstructure:"model" cty:"model" hcl:"model"` + PacketQueues *int `mapstructure:"packet_queues" cty:"packet_queues" hcl:"packet_queues"` + MACAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` + Bridge *string `mapstructure:"bridge" cty:"bridge" hcl:"bridge"` + VLANTag *string `mapstructure:"vlan_tag" cty:"vlan_tag" hcl:"vlan_tag"` + Firewall *bool `mapstructure:"firewall" cty:"firewall" hcl:"firewall"` } // FlatMapstructure returns a new FlatnicConfig. @@ -266,11 +267,12 @@ func (*nicConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spe // The decoded values from this spec will then be applied to a FlatnicConfig. func (*FlatnicConfig) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ - "model": &hcldec.AttrSpec{Name: "model", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "bridge": &hcldec.AttrSpec{Name: "bridge", Type: cty.String, Required: false}, - "vlan_tag": &hcldec.AttrSpec{Name: "vlan_tag", Type: cty.String, Required: false}, - "firewall": &hcldec.AttrSpec{Name: "firewall", Type: cty.Bool, Required: false}, + "model": &hcldec.AttrSpec{Name: "model", Type: cty.String, Required: false}, + "packet_queues": &hcldec.AttrSpec{Name: "packet_queues", Type: cty.Number, Required: false}, + "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, + "bridge": &hcldec.AttrSpec{Name: "bridge", Type: cty.String, Required: false}, + "vlan_tag": &hcldec.AttrSpec{Name: "vlan_tag", Type: cty.String, Required: false}, + "firewall": &hcldec.AttrSpec{Name: "firewall", Type: cty.Bool, Required: false}, } return s } diff --git a/builder/proxmox/config_test.go b/builder/proxmox/config_test.go index e9889ba38..c5667c4ff 100644 --- a/builder/proxmox/config_test.go +++ b/builder/proxmox/config_test.go @@ -8,6 +8,17 @@ import ( "github.com/hashicorp/packer/template" ) +func mandatoryConfig(t *testing.T) map[string]interface{} { + return map[string]interface{}{ + "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json", + "username": "apiuser@pve", + "password": "supersecret", + "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso", + "node": "my-proxmox", + "ssh_username": "root", + } +} + func TestRequiredParameters(t *testing.T) { var c Config _, err := c.Prepare(make(map[string]interface{})) @@ -166,3 +177,48 @@ func TestAgentSetToFalse(t *testing.T) { t.Errorf("Expected Agent to be false, got %t", b.config.Agent) } } + +func TestNetworkAdapterPacketQueueSupport(t *testing.T) { + drivertests := []struct { + expectedToFail bool + model string + }{ + {expectedToFail: false, model: "virtio"}, + {expectedToFail: true, model: "e1000"}, + {expectedToFail: true, model: "e1000-82540em"}, + {expectedToFail: true, model: "e1000-82544gc"}, + {expectedToFail: true, model: "e1000-82545em"}, + {expectedToFail: true, model: "i82551"}, + {expectedToFail: true, model: "i82557b"}, + {expectedToFail: true, model: "i82559er"}, + {expectedToFail: true, model: "ne2k_isa"}, + {expectedToFail: true, model: "ne2k_pci"}, + {expectedToFail: true, model: "pcnet"}, + {expectedToFail: true, model: "rtl8139"}, + {expectedToFail: true, model: "vmxnet3"}, + } + + for _, tt := range drivertests { + device := make(map[string]interface{}) + device["bridge"] = "vmbr0" + device["model"] = tt.model + device["packet_queues"] = 2 + + devices := make([]map[string]interface{}, 0) + devices = append(devices, device) + + cfg := mandatoryConfig(t) + cfg["network_adapters"] = devices + + 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()) + } + } +}