From 7f0de5fc8dc1bf7fd1f3b4c196378883f2e1e33f Mon Sep 17 00:00:00 2001 From: jhawk28 Date: Fri, 14 Feb 2020 11:51:57 -0500 Subject: [PATCH] add ability to define multiple NICs for vsphere-iso (#8739) --- builder/vsphere/driver/vm.go | 72 ++++++++++++------- builder/vsphere/iso/config.hcl2spec.go | 2 + builder/vsphere/iso/step_create.go | 35 ++++++++- builder/vsphere/iso/step_create.hcl2spec.go | 51 ++++++++++--- .../docs/builders/vsphere-iso.html.md.erb | 7 ++ .../iso/_CreateConfig-not-required.html.md | 2 + .../vsphere/iso/_NIC-not-required.html.md | 8 +++ .../builder/vsphere/iso/_NIC-required.html.md | 4 ++ 8 files changed, 141 insertions(+), 40 deletions(-) create mode 100644 website/source/partials/builder/vsphere/iso/_NIC-not-required.html.md create mode 100644 website/source/partials/builder/vsphere/iso/_NIC-required.html.md diff --git a/builder/vsphere/driver/vm.go b/builder/vsphere/driver/vm.go index 06edbdfbd..aa1bae2fc 100644 --- a/builder/vsphere/driver/vm.go +++ b/builder/vsphere/driver/vm.go @@ -44,6 +44,13 @@ type HardwareConfig struct { VideoRAM int64 } +type NIC struct { + Network string // "" for default network + NetworkCard string // example: vmxnet3 + MacAddress string // set mac if want specific address + Passthrough *bool // direct path i/o +} + type CreateConfig struct { DiskThinProvisioned bool DiskControllerType string // example: "scsi", "pvscsi" @@ -57,8 +64,7 @@ type CreateConfig struct { ResourcePool string Datastore string GuestOS string // example: otherGuest - Network string // "" for default network - NetworkCard string // example: vmxnet3 + NICs []NIC USBController bool Version uint // example: 10 Firmware string // efi or bios @@ -509,42 +515,56 @@ func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) } func addNetwork(d *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) { + if len(config.NICs) == 0 { + return nil, errors.New("no network adapters have been defined") + } + var network object.NetworkReference - if config.Network == "" { - h, err := d.FindHost(config.Host) + for _, nic := range config.NICs { + if nic.Network == "" { + h, err := d.FindHost(config.Host) + if err != nil { + return nil, err + } + + i, err := h.Info("network") + if err != nil { + return nil, err + } + + if len(i.Network) > 1 { + return nil, fmt.Errorf("Host has multiple networks. Specify it explicitly") + } + + network = object.NewNetwork(d.client.Client, i.Network[0]) + } else { + var err error + network, err = d.finder.Network(d.ctx, nic.Network) + if err != nil { + return nil, err + } + } + + backing, err := network.EthernetCardBackingInfo(d.ctx) if err != nil { return nil, err } - i, err := h.Info("network") + device, err := object.EthernetCardTypes().CreateEthernetCard(nic.NetworkCard, backing) if err != nil { return nil, err } - if len(i.Network) > 1 { - return nil, fmt.Errorf("Host has multiple networks. Specify it explicitly") + card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + if nic.MacAddress != "" { + card.AddressType = string(types.VirtualEthernetCardMacTypeManual) + card.MacAddress = nic.MacAddress } + card.UptCompatibilityEnabled = nic.Passthrough - network = object.NewNetwork(d.client.Client, i.Network[0]) - } else { - var err error - network, err = d.finder.Network(d.ctx, config.Network) - if err != nil { - return nil, err - } + devices = append(devices, device) } - - backing, err := network.EthernetCardBackingInfo(d.ctx) - if err != nil { - return nil, err - } - - device, err := object.EthernetCardTypes().CreateEthernetCard(config.NetworkCard, backing) - if err != nil { - return nil, err - } - - return append(devices, device), nil + return devices, nil } func (vm *VirtualMachine) AddCdrom(controllerType string, isoPath string) error { diff --git a/builder/vsphere/iso/config.hcl2spec.go b/builder/vsphere/iso/config.hcl2spec.go index 222791485..a1c489147 100644 --- a/builder/vsphere/iso/config.hcl2spec.go +++ b/builder/vsphere/iso/config.hcl2spec.go @@ -32,6 +32,7 @@ type FlatConfig struct { DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"` Network *string `mapstructure:"network" cty:"network"` NetworkCard *string `mapstructure:"network_card" cty:"network_card"` + NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"` USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"` Notes *string `mapstructure:"notes" cty:"notes"` VMName *string `mapstructure:"vm_name" cty:"vm_name"` @@ -152,6 +153,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false}, "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, "network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false}, + "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.Bool, Required: false}, "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, diff --git a/builder/vsphere/iso/step_create.go b/builder/vsphere/iso/step_create.go index b6e80aacf..a78c5d34e 100644 --- a/builder/vsphere/iso/step_create.go +++ b/builder/vsphere/iso/step_create.go @@ -1,5 +1,5 @@ //go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type CreateConfig +//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig package iso @@ -13,6 +13,17 @@ import ( "github.com/hashicorp/packer/packer" ) +type NIC struct { + // Set network VM will be connected to. + Network string `mapstructure:"network"` + // Set VM network card type. Example `vmxnet3`. + NetworkCard string `mapstructure:"network_card" required:"true"` + // Set network card MAC address + MacAddress string `mapstructure:"mac_address"` + // Enable DirectPath I/O passthrough + Passthrough *bool `mapstructure:"passthrough"` +} + type CreateConfig struct { // Set VM hardware version. Defaults to the most current VM hardware // version supported by vCenter. See @@ -35,6 +46,8 @@ type CreateConfig struct { Network string `mapstructure:"network"` // Set VM network card type. Example `vmxnet3`. NetworkCard string `mapstructure:"network_card"` + // Network adapters + NICs []NIC `mapstructure:"network_adapters"` // Create USB controller for virtual machine. Defaults to `false`. USBController bool `mapstructure:"usb_controller"` // VM notes. @@ -83,6 +96,23 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste } ui.Say("Creating VM...") + + // add network/network card an the first nic for backwards compatibility in the type is defined + var networkCards []driver.NIC + if s.Config.NetworkCard != "" { + networkCards = append(networkCards, driver.NIC{ + NetworkCard: s.Config.NetworkCard, + Network: s.Config.Network}) + } + for _, nic := range s.Config.NICs { + networkCards = append(networkCards, driver.NIC{ + Network: nic.Network, + NetworkCard: nic.NetworkCard, + MacAddress: nic.MacAddress, + Passthrough: nic.Passthrough, + }) + } + vm, err = d.CreateVM(&driver.CreateConfig{ DiskThinProvisioned: s.Config.DiskThinProvisioned, DiskControllerType: s.Config.DiskControllerType, @@ -94,8 +124,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste ResourcePool: s.Location.ResourcePool, Datastore: s.Location.Datastore, GuestOS: s.Config.GuestOSType, - Network: s.Config.Network, - NetworkCard: s.Config.NetworkCard, + NICs: networkCards, USBController: s.Config.USBController, Version: s.Config.Version, Firmware: s.Config.Firmware, diff --git a/builder/vsphere/iso/step_create.hcl2spec.go b/builder/vsphere/iso/step_create.hcl2spec.go index a9f4342f9..e3eb36697 100644 --- a/builder/vsphere/iso/step_create.hcl2spec.go +++ b/builder/vsphere/iso/step_create.hcl2spec.go @@ -1,4 +1,4 @@ -// Code generated by "mapstructure-to-hcl2 -type CreateConfig"; DO NOT EDIT. +// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig"; DO NOT EDIT. package iso import ( @@ -9,16 +9,17 @@ import ( // FlatCreateConfig is an auto-generated flat version of CreateConfig. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatCreateConfig struct { - Version *uint `mapstructure:"vm_version" cty:"vm_version"` - GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"` - Firmware *string `mapstructure:"firmware" cty:"firmware"` - DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"` - DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` - DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"` - Network *string `mapstructure:"network" cty:"network"` - NetworkCard *string `mapstructure:"network_card" cty:"network_card"` - USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"` - Notes *string `mapstructure:"notes" cty:"notes"` + Version *uint `mapstructure:"vm_version" cty:"vm_version"` + GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"` + Firmware *string `mapstructure:"firmware" cty:"firmware"` + DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"` + DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` + DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"` + Network *string `mapstructure:"network" cty:"network"` + NetworkCard *string `mapstructure:"network_card" cty:"network_card"` + NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"` + USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"` + Notes *string `mapstructure:"notes" cty:"notes"` } // FlatMapstructure returns a new FlatCreateConfig. @@ -41,8 +42,36 @@ func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec { "disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false}, "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, "network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false}, + "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.Bool, Required: false}, "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, } return s } + +// FlatNIC is an auto-generated flat version of NIC. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatNIC struct { + Network *string `mapstructure:"network" cty:"network"` + NetworkCard *string `mapstructure:"network_card" required:"true" cty:"network_card"` + MacAddress *string `mapstructure:"mac_address" cty:"mac_address"` + Passthrough *bool `mapstructure:"passthrough" cty:"passthrough"` +} + +// FlatMapstructure returns a new FlatNIC. +// FlatNIC is an auto-generated flat version of NIC. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*NIC) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { return new(FlatNIC) } + +// HCL2Spec returns the hcl spec of a NIC. +// This spec is used by HCL to read the fields of NIC. +// The decoded values from this spec will then be applied to a FlatNIC. +func (*FlatNIC) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, + "network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false}, + "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, + "passthrough": &hcldec.AttrSpec{Name: "passthrough", Type: cty.Bool, Required: false}, + } + return s +} diff --git a/website/source/docs/builders/vsphere-iso.html.md.erb b/website/source/docs/builders/vsphere-iso.html.md.erb index bf05eb64a..357268686 100644 --- a/website/source/docs/builders/vsphere-iso.html.md.erb +++ b/website/source/docs/builders/vsphere-iso.html.md.erb @@ -67,6 +67,9 @@ necessary for this build to succeed and can be found further down the page. ### Create Configuration <%= partial "partials/builder/vsphere/iso/CreateConfig-not-required" %> +### Network Adapter Configuration +<%= partial "partials/builder/vsphere/iso/NIC-required" %> + ### Floppy Configuration <%= partial "partials/builder/vsphere/iso/FloppyConfig-not-required" %> @@ -79,6 +82,10 @@ necessary for this build to succeed and can be found further down the page. <%= partial "partials/helper/communicator/Config-not-required" %> +#### Optional Network Adapter fields: + +<%= partial "partials/builder/vsphere/iso/NIC-not-required" %> + #### Optional SSH fields: <%= partial "partials/helper/communicator/SSH-not-required" %> diff --git a/website/source/partials/builder/vsphere/iso/_CreateConfig-not-required.html.md b/website/source/partials/builder/vsphere/iso/_CreateConfig-not-required.html.md index 09e632ee9..c27601606 100644 --- a/website/source/partials/builder/vsphere/iso/_CreateConfig-not-required.html.md +++ b/website/source/partials/builder/vsphere/iso/_CreateConfig-not-required.html.md @@ -21,6 +21,8 @@ - `network_card` (string) - Set VM network card type. Example `vmxnet3`. +- `network_adapters` ([]NIC) - Network adapters + - `usb_controller` (bool) - Create USB controller for virtual machine. Defaults to `false`. - `notes` (string) - VM notes. diff --git a/website/source/partials/builder/vsphere/iso/_NIC-not-required.html.md b/website/source/partials/builder/vsphere/iso/_NIC-not-required.html.md new file mode 100644 index 000000000..32b56d663 --- /dev/null +++ b/website/source/partials/builder/vsphere/iso/_NIC-not-required.html.md @@ -0,0 +1,8 @@ + + +- `network` (string) - Set network VM will be connected to. + +- `mac_address` (string) - Set network card MAC address + +- `passthrough` (\*bool) - Enable DirectPath I/O passthrough + \ No newline at end of file diff --git a/website/source/partials/builder/vsphere/iso/_NIC-required.html.md b/website/source/partials/builder/vsphere/iso/_NIC-required.html.md new file mode 100644 index 000000000..81b78c372 --- /dev/null +++ b/website/source/partials/builder/vsphere/iso/_NIC-required.html.md @@ -0,0 +1,4 @@ + + +- `network_card` (string) - Set VM network card type. Example `vmxnet3`. + \ No newline at end of file