Skip to content

Commit

Permalink
feat: expand switch / adapter configuration.
Browse files Browse the repository at this point in the history
Signed-off-by: Greg Althaus <[email protected]>
  • Loading branch information
galthaus committed Mar 20, 2024
1 parent 90f3b30 commit 1280b76
Show file tree
Hide file tree
Showing 32 changed files with 801 additions and 627 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
main
dist/*
packer-plugin-scaffolding
packer-plugin-hyperv
.docs
15 changes: 9 additions & 6 deletions .web-docs/components/builder/iso/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,10 @@ created, must be empty prior to running the builder. By default this is
try and determine the switch to use by looking for an external switch
that is up and running.

- `switches_names` ([]string) - The name of the switches to connect the virtual
- `switch_type` (string) - The type of the main switch to connect the virtual
machine to. By default, leaving this value unset will cause Packer to
not use any additional switches.
try and determine the switch to use by looking for an external switch
that is up and running.

- `switch_vlan_id` (string) - This is the VLAN of the virtual switch's
network card. By default, none is set. If none is set then a VLAN is not
Expand All @@ -271,14 +272,16 @@ created, must be empty prior to running the builder. By default this is
the default main virtual network card. The MAC address must be a string with
no delimiters, for example "0000deadbeef".

- `mac_addresses` ([]string) - This allows a specific MAC addresses to be used on
the optional virtual network cards set in `switches_names` array. The MAC addresses must be strings with
no delimiters, for example "0000deadbeef".

- `vlan_id` (string) - This is the VLAN of the virtual machine's network
card for the new virtual machine. By default none is set. If none is set
then VLANs are not set on the virtual machine's network card.

- `switch_config` ([]SwitchConfig) - This allows for multiple switches to be configured.
This should be used exclusively with SwitchName, SwitchVlanId, and MacAddress.

- `adapter_config` ([]AdapterConfig) - This allows for multiple switches to be configured.
This should be used exclusively with MacAddress and VlanId.

- `cpus` (uint) - The number of CPUs the virtual machine should use. If
this isn't specified, the default is 1 CPU.

Expand Down
15 changes: 9 additions & 6 deletions .web-docs/components/builder/vmcx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,10 @@ In HCL2:
try and determine the switch to use by looking for an external switch
that is up and running.

- `switches_names` ([]string) - The name of the switches to connect the virtual
- `switch_type` (string) - The type of the main switch to connect the virtual
machine to. By default, leaving this value unset will cause Packer to
not use any additional switches.
try and determine the switch to use by looking for an external switch
that is up and running.

- `switch_vlan_id` (string) - This is the VLAN of the virtual switch's
network card. By default, none is set. If none is set then a VLAN is not
Expand All @@ -298,14 +299,16 @@ In HCL2:
the default main virtual network card. The MAC address must be a string with
no delimiters, for example "0000deadbeef".

- `mac_addresses` ([]string) - This allows a specific MAC addresses to be used on
the optional virtual network cards set in `switches_names` array. The MAC addresses must be strings with
no delimiters, for example "0000deadbeef".

- `vlan_id` (string) - This is the VLAN of the virtual machine's network
card for the new virtual machine. By default none is set. If none is set
then VLANs are not set on the virtual machine's network card.

- `switch_config` ([]SwitchConfig) - This allows for multiple switches to be configured.
This should be used exclusively with SwitchName, SwitchVlanId, and MacAddress.

- `adapter_config` ([]AdapterConfig) - This allows for multiple switches to be configured.
This should be used exclusively with MacAddress and VlanId.

- `cpus` (uint) - The number of CPUs the virtual machine should use. If
this isn't specified, the default is 1 CPU.

Expand Down
35 changes: 35 additions & 0 deletions builder/hyperv/common/adapter_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

//go:generate packer-sdc struct-markdown
//go:generate packer-sdc mapstructure-to-hcl2 -type AdapterConfig

package common

import (
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
)

type AdapterConfig struct {
// The name of the network adapter.
// By default, leaving this value unset will cause Packer to
// try and determine the switch to use by looking for an external switch
// that is up and running.
Name string `mapstructure:"adapter_name" required:"false"`
// The name of the switch for this adapter
SwitchName string `mapstructure:"switch_name" required:"false"`
// This is the VLAN of the virtual switch's
// network card. By default, none is set. If none is set then a VLAN is not
// set on the switch's network card. If this value is set it should match
// the VLAN specified in by vlan_id.
VlanId string `mapstructure:"vlan_id" required:"false"`
// This allows a specific MAC address to be used on
// the default main virtual network card. The MAC address must be a string with
// no delimiters, for example "037777777777deadbeef".
MacAddress string `mapstructure:"mac_address" required:"false"`
}

func (ac AdapterConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) ([]error, []string) {
return nil, nil
}
37 changes: 37 additions & 0 deletions builder/hyperv/common/adapter_config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

134 changes: 115 additions & 19 deletions builder/hyperv/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ type CommonConfig struct {
// try and determine the switch to use by looking for an external switch
// that is up and running.
SwitchName string `mapstructure:"switch_name" required:"false"`
// The name of the switches to connect the virtual
// The type of the main switch to connect the virtual
// machine to. By default, leaving this value unset will cause Packer to
// not use any additional switches.
SwitchesNames []string `mapstructure:"switches_names" required:"false"`
// try and determine the switch to use by looking for an external switch
// that is up and running.
SwitchType string `mapstructure:"switch_type" required:"false"`
// This is the VLAN of the virtual switch's
// network card. By default, none is set. If none is set then a VLAN is not
// set on the switch's network card. If this value is set it should match
Expand All @@ -92,14 +93,16 @@ type CommonConfig struct {
// the default main virtual network card. The MAC address must be a string with
// no delimiters, for example "0000deadbeef".
MacAddress string `mapstructure:"mac_address" required:"false"`
// This allows a specific MAC addresses to be used on
// the optional virtual network cards set in `switches_names` array. The MAC addresses must be strings with
// no delimiters, for example "0000deadbeef".
MacAddresses []string `mapstructure:"mac_addresses" required:"false"`
// This is the VLAN of the virtual machine's network
// card for the new virtual machine. By default none is set. If none is set
// then VLANs are not set on the virtual machine's network card.
VlanId string `mapstructure:"vlan_id" required:"false"`
// This allows for multiple switches to be configured.
// This should be used exclusively with SwitchName, SwitchVlanId, and MacAddress.
SwitchConfigs []SwitchConfig `mapstructure:"switch_config" required:"false"`
// This allows for multiple switches to be configured.
// This should be used exclusively with MacAddress and VlanId.
AdapterConfigs []AdapterConfig `mapstructure:"adapter_config" required:"false"`
// The number of CPUs the virtual machine should use. If
// this isn't specified, the default is 1 CPU.
Cpu uint `mapstructure:"cpus" required:"false"`
Expand Down Expand Up @@ -205,9 +208,110 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
log.Printf("%s: %v", "VMName", c.VMName)
}

if c.SwitchName == "" {
c.SwitchName = c.detectSwitchName(pc.PackerBuildName)
log.Printf("Using switch %s", c.SwitchName)
// Validation of switch config and switch parameters
// The end result of this section is the unification of all Switch Parameters into SwitchConfigs.
if (c.SwitchName != "" || c.SwitchType != "" || c.SwitchVlanId != "" || c.MacAddress != "" || c.VlanId != "") &&
(len(c.AdapterConfigs) > 0 || len(c.SwitchConfigs) > 0) {
err := fmt.Errorf("SwitchName/SwitchType/SwitchVlanId/MacAddress/VlanId and SwitchConfig/AdapterConfig not allowed.")
errs = append(errs, err)
} else {
if c.SwitchName != "" || c.SwitchType != "" || c.SwitchVlanId != "" || c.MacAddress != "" || c.VlanId != "" {
if c.SwitchType != "" {
warns = append(warns, "SwitchType is deprecated and should be converted to SwitchConfigs")
}
if c.SwitchName != "" {
warns = append(warns, "SwitchName is deprecated and should be converted to SwitchConfigs")
} else {
c.SwitchName = c.detectSwitchName(pc.PackerBuildName)
if c.SwitchType == "" {
c.SwitchType = SwitchTypeExternal
}
log.Printf("Using switch %s", c.SwitchName)
}
if c.SwitchVlanId != "" {
warns = append(warns, "SwitchVlanId is deprecated and should be converted to SwitchConfigs")
}
if c.MacAddress != "" {
warns = append(warns, "MacAddress is deprecated and should be converted to SwitchConfigs")
}
if c.VlanId != "" {
warns = append(warns, "VlanId is deprecated and should be converted to SwitchConfigs")
}
if c.SwitchVlanId != "" {
if c.SwitchVlanId != c.VlanId {
warning := fmt.Sprintf("Switch network adaptor vlan should match virtual machine network adaptor " +
"vlan. The switch will not be able to see traffic from the VM.")
warns = Appendwarns(warns, warning)
}
}

c.SwitchConfigs = []SwitchConfig{{
SwitchName: c.SwitchName,
SwitchType: c.SwitchType,
SwitchVlanId: c.SwitchVlanId,
}}
c.AdapterConfigs = []AdapterConfig{{
Name: c.VMName,
VlanId: c.VlanId,
MacAddress: c.MacAddress,
SwitchName: c.SwitchName,
}}

// Make sure we don't get confused....
c.VlanId = ""
c.MacAddress = ""
c.SwitchName = ""
c.SwitchType = ""
c.SwitchVlanId = ""
} else {
// If switchConfigs and adapterConfigs are not 0, assume the user knows what they are doing somewhat.
// Make sure the structs are valid, but don't create things for them.
if len(c.SwitchConfigs) == 0 {
swname := c.detectSwitchName(pc.PackerBuildName)
log.Printf("Using switch %s", swname)
c.SwitchConfigs = []SwitchConfig{{SwitchName: swname}}
}
for ii, sw := range c.SwitchConfigs {
if sw.SwitchName == "" {
err := fmt.Errorf("SwitchName for Switch(%d) requires a name", ii)
errs = append(errs, err)
}
}
if c.SwitchConfigs[0].SwitchType == "" {
c.SwitchConfigs[0].SwitchType = SwitchTypeExternal
}
if len(c.AdapterConfigs) == 0 {
c.AdapterConfigs = []AdapterConfig{}
for ii, sw := range c.SwitchConfigs {
name := c.VMName
if ii != 0 {
name = fmt.Sprintf("%s-%d", c.VMName, ii)
}
c.AdapterConfigs = append(c.AdapterConfigs, AdapterConfig{Name: name, SwitchName: sw.SwitchName})
}
} else {
for ii, adp := range c.AdapterConfigs {
found := false
for _, sw := range c.SwitchConfigs {
if sw.SwitchName == adp.SwitchName {
found = true
break
}
}
if !found {
err := fmt.Errorf("Network Adapter %d (%s) requires a switch that is not defined: %s", ii, adp.Name, adp.SwitchName)
errs = append(errs, err)
}
if adp.Name == "" {
name := c.VMName
if ii != 0 {
name = fmt.Sprintf("%s-%d", c.VMName, ii)
}
adp.Name = name
}
}
}
}
}

if c.Generation < 1 || c.Generation > 2 {
Expand Down Expand Up @@ -341,14 +445,6 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
}
}

if c.SwitchVlanId != "" {
if c.SwitchVlanId != c.VlanId {
warning := fmt.Sprintf("Switch network adaptor vlan should match virtual machine network adaptor " +
"vlan. The switch will not be able to see traffic from the VM.")
warns = Appendwarns(warns, warning)
}
}

err := c.checkDiskBlockSize()
if err != nil {
errs = append(errs, err)
Expand Down Expand Up @@ -396,7 +492,7 @@ func (c *CommonConfig) checkHostAvailableMemory() string {
freeMB := powershell.GetHostAvailableMemory()

if (freeMB - float64(c.RamSize)) < LowRam {
return "Hyper-V might fail to create a VM if there is not enough free memory in the system."
return fmt.Sprintf("Hyper-V might fail to create a VM if there is not enough free memory in the system. (%v, %v, %v)", freeMB, float64(c.RamSize), LowRam)
}
}

Expand Down
21 changes: 9 additions & 12 deletions builder/hyperv/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,35 +54,32 @@ type Driver interface {
GetVirtualMachineNetworkAdapterAddress(string) (string, error)

//Set the vlan to use for switch
SetNetworkAdapterVlanId(string, string) error

//Set the vlan to use for machine
CreateVirtualMachineNetworkAdapter(string, string, string, bool) error
SetVirtualMachineVlanId(string, string) error

//Set the vlan to use for machine
SetNetworkAdapterVlanId(string, string) error
SetVmNetworkAdapterMacAddress(string, string) error

//Replace the network adapter with a (non-)legacy adapter
ReplaceVirtualMachineNetworkAdapter(string, bool) error

// Not used currently and likely broken.
UntagVirtualMachineNetworkAdapterVlan(string, string) error

CreateExternalVirtualSwitch(string, string) error

GetVirtualMachineSwitchName(string) (string, error)

ConnectVirtualMachineNetworkAdapterToSwitch(string, string) error
GetVirtualMachineSwitchName(string) (string, error)

// Switch Management Functions
CreateVirtualSwitch(string, string) (bool, error)

CreateExternalVirtualSwitch(string) (bool, error)
DeleteVirtualSwitch(string) error

CheckVMName(string) error

CreateVirtualMachine(string, string, string, int64, int64, int64, string, []string, []string, uint, bool, bool, string) error
CreateVirtualMachine(string, string, string, int64, int64, int64, string, uint, bool, bool, string) error

AddVirtualMachineHardDrive(string, string, string, int64, int64, string) error

CloneVirtualMachine(string, string, string, bool, string, string, string, int64, string, []string, []string, bool) error
CloneVirtualMachine(string, string, string, bool, string, string, string, int64, string, bool) error

ResizeVirtualMachineVhd(string, uint64) error

Expand Down
Loading

0 comments on commit 1280b76

Please sign in to comment.