0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-29 18:21:10 +00:00

chore(vm): refactoring: extract network device code from vm.go (#1127)

chore(vm): refactoring: extract network code

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2024-03-15 21:06:30 -04:00 committed by GitHub
parent 279b41a0e4
commit 29b5438faf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 837 additions and 742 deletions

View File

@ -28,7 +28,7 @@ func TestDatastoresInstantiation(t *testing.T) {
func TestDatastoresSchema(t *testing.T) {
t.Parallel()
s := Datastores()
s := Datastores().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentDatastoresNodeName,

View File

@ -28,7 +28,7 @@ func TestDNSInstantiation(t *testing.T) {
func TestDNSSchema(t *testing.T) {
t.Parallel()
s := DNS()
s := DNS().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentDNSNodeName,

View File

@ -25,18 +25,18 @@ func TestAliasSchemaInstantiation(t *testing.T) {
func TestAliasSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: AliasSchema()}
s := AliasSchema()
test.AssertRequiredArguments(t, &r, []string{
test.AssertRequiredArguments(t, s, []string{
mkAliasName,
})
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkAliasCIDR,
mkAliasComment,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkAliasName: schema.TypeString,
mkAliasCIDR: schema.TypeString,
mkAliasComment: schema.TypeString,

View File

@ -25,13 +25,13 @@ func TestAliasesSchemaInstantiation(t *testing.T) {
func TestAliasesSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: AliasesSchema()}
s := AliasesSchema()
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkAliasesAliasNames,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkAliasesAliasNames: schema.TypeList,
})
}

View File

@ -25,24 +25,24 @@ func TestIPSetSchemaInstantiation(t *testing.T) {
func TestIPSetSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: IPSetSchema()}
s := IPSetSchema()
test.AssertRequiredArguments(t, &r, []string{
test.AssertRequiredArguments(t, s, []string{
mkIPSetName,
})
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkIPSetCIDR,
mkIPSetCIDRComment,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkIPSetName: schema.TypeString,
mkIPSetCIDR: schema.TypeList,
mkIPSetCIDRComment: schema.TypeString,
})
cird := test.AssertNestedSchemaExistence(t, &r, mkIPSetCIDR)
cird := test.AssertNestedSchemaExistence(t, s, mkIPSetCIDR)
test.AssertComputedAttributes(t, cird, []string{
mkIPSetCIDRName,

View File

@ -25,13 +25,13 @@ func TestIPSetsSchemaInstantiation(t *testing.T) {
func TestIPSetsSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: IPSetsSchema()}
s := IPSetsSchema()
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkIPSetsIPSetNames,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkIPSetsIPSetNames: schema.TypeList,
})
}

View File

@ -25,14 +25,14 @@ func TestRuleSchemaInstantiation(t *testing.T) {
func TestRuleSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: RuleSchema()}
s := RuleSchema()
test.AssertRequiredArguments(t, &r, []string{
test.AssertRequiredArguments(t, s, []string{
mkRuleAction,
mkRuleType,
})
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkRuleComment,
mkRuleDest,
mkRuleDPort,
@ -45,7 +45,7 @@ func TestRuleSchema(t *testing.T) {
mkRuleSPort,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkRulePos: schema.TypeInt,
mkRuleAction: schema.TypeString,
mkRuleType: schema.TypeString,

View File

@ -25,18 +25,18 @@ func TestSecurityGroupSchemaInstantiation(t *testing.T) {
func TestSecurityGroupSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: SecurityGroupSchema()}
s := SecurityGroupSchema()
test.AssertRequiredArguments(t, &r, []string{
test.AssertRequiredArguments(t, s, []string{
mkSecurityGroupName,
})
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkSecurityGroupComment,
mkRules,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkSecurityGroupName: schema.TypeString,
mkSecurityGroupComment: schema.TypeString,
mkRules: schema.TypeList,

View File

@ -25,13 +25,13 @@ func TestSecurityGroupsSchemaInstantiation(t *testing.T) {
func TestSecurityGroupsSchema(t *testing.T) {
t.Parallel()
r := schema.Resource{Schema: SecurityGroupsSchema()}
s := SecurityGroupsSchema()
test.AssertComputedAttributes(t, &r, []string{
test.AssertComputedAttributes(t, s, []string{
mkSecurityGroupsSecurityGroupNames,
})
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkSecurityGroupsSecurityGroupNames: schema.TypeList,
})
}

View File

@ -28,7 +28,7 @@ func TestGroupInstantiation(t *testing.T) {
func TestGroupSchema(t *testing.T) {
t.Parallel()
s := Group()
s := Group().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentGroupID,

View File

@ -28,7 +28,7 @@ func TestGroupsInstantiation(t *testing.T) {
func TestGroupsSchema(t *testing.T) {
t.Parallel()
s := Groups()
s := Groups().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentGroupsComments,

View File

@ -28,7 +28,7 @@ func TestHostsInstantiation(t *testing.T) {
func TestHostsSchema(t *testing.T) {
t.Parallel()
s := Hosts()
s := Hosts().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentHostsNodeName,

View File

@ -28,7 +28,7 @@ func TestNodesInstantiation(t *testing.T) {
func TestNodesSchema(t *testing.T) {
t.Parallel()
s := Nodes()
s := Nodes().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentNodesCPUCount,

View File

@ -28,7 +28,7 @@ func TestPoolInstantiation(t *testing.T) {
func TestPoolSchema(t *testing.T) {
t.Parallel()
s := Pool()
s := Pool().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentPoolPoolID,

View File

@ -28,7 +28,7 @@ func TestPoolsInstantiation(t *testing.T) {
func TestPoolsSchema(t *testing.T) {
t.Parallel()
s := Pools()
s := Pools().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentPoolsPoolIDs,

View File

@ -28,7 +28,7 @@ func TestRoleInstantiation(t *testing.T) {
func TestRoleSchema(t *testing.T) {
t.Parallel()
s := Role()
s := Role().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentRoleID,

View File

@ -28,7 +28,7 @@ func TestRolesInstantiation(t *testing.T) {
func TestRolesSchema(t *testing.T) {
t.Parallel()
s := Roles()
s := Roles().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentRolesPrivileges,

View File

@ -28,7 +28,7 @@ func TestTimeInstantiation(t *testing.T) {
func TestTimeSchema(t *testing.T) {
t.Parallel()
s := Time()
s := Time().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentTimeNodeName,

View File

@ -28,7 +28,7 @@ func TestUserInstantiation(t *testing.T) {
func TestUserSchema(t *testing.T) {
t.Parallel()
s := User()
s := User().Schema
test.AssertRequiredArguments(t, s, []string{
mkDataSourceVirtualEnvironmentUserUserID,

View File

@ -28,7 +28,7 @@ func TestUsersInstantiation(t *testing.T) {
func TestUsersSchema(t *testing.T) {
t.Parallel()
s := Users()
s := Users().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentUsersComments,

View File

@ -29,7 +29,7 @@ func TestVMInstantiation(t *testing.T) {
func TestVMSchema(t *testing.T) {
t.Parallel()
s := VM()
s := VM().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentVMName,

View File

@ -29,7 +29,7 @@ func TestVMsInstantiation(t *testing.T) {
func TestVMsSchema(t *testing.T) {
t.Parallel()
s := VMs()
s := VMs().Schema
test.AssertComputedAttributes(t, s, []string{
mkDataSourceVirtualEnvironmentVMs,

View File

@ -28,9 +28,7 @@ func TestProviderInstantiation(t *testing.T) {
func TestProviderSchema(t *testing.T) {
t.Parallel()
s := &schema.Resource{
Schema: ProxmoxVirtualEnvironment().Schema,
}
s := ProxmoxVirtualEnvironment().Schema
test.AssertOptionalArguments(t, s, []string{
mkProviderUsername,

View File

@ -28,7 +28,7 @@ func TestCertificateInstantiation(t *testing.T) {
func TestCertificateSchema(t *testing.T) {
t.Parallel()
s := Certificate()
s := Certificate().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentCertificateCertificate,

View File

@ -26,7 +26,7 @@ func TestSecurityGroupInstantiation(t *testing.T) {
func TestSecurityGroupSchema(t *testing.T) {
t.Parallel()
s := SecurityGroup()
s := SecurityGroup().Schema
test.AssertRequiredArguments(t, s, []string{
mkSecurityGroupName,

View File

@ -28,7 +28,7 @@ func TestContainerInstantiation(t *testing.T) {
func TestContainerSchema(t *testing.T) {
t.Parallel()
s := Container()
s := Container().Schema
test.AssertRequiredArguments(t, s, []string{
mkNodeName,

View File

@ -28,7 +28,7 @@ func TestDNSInstantiation(t *testing.T) {
func TestDNSSchema(t *testing.T) {
t.Parallel()
s := DNS()
s := DNS().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentDNSDomain,

View File

@ -29,7 +29,7 @@ func TestFileInstantiation(t *testing.T) {
func TestFileSchema(t *testing.T) {
t.Parallel()
s := File()
s := File().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentFileDatastoreID,

View File

@ -25,7 +25,7 @@ func TestAliasInstantiation(t *testing.T) {
func TestAliasSchema(t *testing.T) {
t.Parallel()
s := Alias()
s := Alias().Schema
test.AssertRequiredArguments(t, s, []string{
mkAliasName,

View File

@ -26,7 +26,7 @@ func TestIPSetInstantiation(t *testing.T) {
func TestIPSetSchema(t *testing.T) {
t.Parallel()
s := IPSet()
s := IPSet().Schema
test.AssertRequiredArguments(t, s, []string{
mkIPSetName,

View File

@ -25,7 +25,7 @@ func TestOptionsInstantiation(t *testing.T) {
func TestOptionsSchema(t *testing.T) {
t.Parallel()
s := Options()
s := Options().Schema
test.AssertOptionalArguments(t, s, []string{
mkDHCP,

View File

@ -25,7 +25,7 @@ func TestRuleInstantiation(t *testing.T) {
func TestRuleSchema(t *testing.T) {
t.Parallel()
rules := Rules()
rules := Rules().Schema
test.AssertRequiredArguments(t, rules, []string{
MkRule,

View File

@ -28,7 +28,7 @@ func TestGroupInstantiation(t *testing.T) {
func TestGroupSchema(t *testing.T) {
t.Parallel()
s := Group()
s := Group().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentGroupID,

View File

@ -28,7 +28,7 @@ func TestHostsInstantiation(t *testing.T) {
func TestHostsSchema(t *testing.T) {
t.Parallel()
s := Hosts()
s := Hosts().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentHostsEntry,

View File

@ -28,7 +28,7 @@ func TestPoolInstantiation(t *testing.T) {
func TestPoolSchema(t *testing.T) {
t.Parallel()
s := Pool()
s := Pool().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentPoolPoolID,

View File

@ -28,7 +28,7 @@ func TestRoleInstantiation(t *testing.T) {
func TestRoleSchema(t *testing.T) {
t.Parallel()
s := Role()
s := Role().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentRolePrivileges,

View File

@ -28,7 +28,7 @@ func TestTimeInstantiation(t *testing.T) {
func TestTimeSchema(t *testing.T) {
t.Parallel()
s := Time()
s := Time().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentTimeNodeName,

View File

@ -28,7 +28,7 @@ func TestUserInstantiation(t *testing.T) {
func TestUserSchema(t *testing.T) {
t.Parallel()
s := User()
s := User().Schema
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentUserUserID,

View File

@ -0,0 +1,53 @@
package disk
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
)
func TestVMSchema(t *testing.T) {
t.Parallel()
s := Schema()
diskSchema := test.AssertNestedSchemaExistence(t, s, MkDisk)
test.AssertOptionalArguments(t, diskSchema, []string{
mkDiskDatastoreID,
mkDiskPathInDatastore,
mkDiskFileFormat,
mkDiskFileID,
mkDiskSize,
})
test.AssertValueTypes(t, diskSchema, map[string]schema.ValueType{
mkDiskDatastoreID: schema.TypeString,
mkDiskPathInDatastore: schema.TypeString,
mkDiskFileFormat: schema.TypeString,
mkDiskFileID: schema.TypeString,
mkDiskSize: schema.TypeInt,
})
diskSpeedSchema := test.AssertNestedSchemaExistence(
t,
diskSchema,
mkDiskSpeed,
)
test.AssertOptionalArguments(t, diskSpeedSchema, []string{
mkDiskSpeedRead,
mkDiskSpeedReadBurstable,
mkDiskSpeedWrite,
mkDiskSpeedWriteBurstable,
})
test.AssertValueTypes(t, diskSpeedSchema, map[string]schema.ValueType{
mkDiskSpeedRead: schema.TypeInt,
mkDiskSpeedReadBurstable: schema.TypeInt,
mkDiskSpeedWrite: schema.TypeInt,
mkDiskSpeedWriteBurstable: schema.TypeInt,
})
}

View File

@ -0,0 +1,276 @@
package network
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
// GetNetworkDeviceObjects returns a list of network devices from the resource data.
func GetNetworkDeviceObjects(d *schema.ResourceData) (vms.CustomNetworkDevices, error) {
networkDevice := d.Get(MkNetworkDevice).([]interface{})
networkDeviceObjects := make(vms.CustomNetworkDevices, len(networkDevice))
for i, networkDeviceEntry := range networkDevice {
block := networkDeviceEntry.(map[string]interface{})
bridge := block[mkNetworkDeviceBridge].(string)
enabled := block[mkNetworkDeviceEnabled].(bool)
firewall := types.CustomBool(block[mkNetworkDeviceFirewall].(bool))
macAddress := block[mkNetworkDeviceMACAddress].(string)
model := block[mkNetworkDeviceModel].(string)
queues := block[mkNetworkDeviceQueues].(int)
rateLimit := block[mkNetworkDeviceRateLimit].(float64)
vlanID := block[mkNetworkDeviceVLANID].(int)
trunks := block[mkNetworkDeviceTrunks].(string)
mtu := block[mkNetworkDeviceMTU].(int)
device := vms.CustomNetworkDevice{
Enabled: enabled,
Firewall: &firewall,
Model: model,
}
if bridge != "" {
device.Bridge = &bridge
}
if macAddress != "" {
device.MACAddress = &macAddress
}
if queues != 0 {
device.Queues = &queues
}
if rateLimit != 0 {
device.RateLimit = &rateLimit
}
if vlanID != 0 {
device.Tag = &vlanID
}
if trunks != "" {
splitTrunks := strings.Split(trunks, ";")
var trunksAsInt []int
for _, numStr := range splitTrunks {
num, err := strconv.Atoi(numStr)
if err != nil {
return nil, fmt.Errorf("error parsing trunks: %w", err)
}
trunksAsInt = append(trunksAsInt, num)
}
device.Trunks = trunksAsInt
}
if mtu != 0 {
device.MTU = &mtu
}
networkDeviceObjects[i] = device
}
return networkDeviceObjects, nil
}
// ReadNetworkDeviceObjects reads the network device objects from the resource data.
func ReadNetworkDeviceObjects(d *schema.ResourceData, vmConfig *vms.GetResponseData) diag.Diagnostics {
var diags diag.Diagnostics
// Compare the network devices to those stored in the state.
currentNetworkDeviceList := d.Get(MkNetworkDevice).([]interface{})
macAddresses := make([]interface{}, MaxNetworkDevices)
networkDeviceLast := -1
networkDeviceList := make([]interface{}, MaxNetworkDevices)
networkDeviceObjects := []*vms.CustomNetworkDevice{
vmConfig.NetworkDevice0,
vmConfig.NetworkDevice1,
vmConfig.NetworkDevice2,
vmConfig.NetworkDevice3,
vmConfig.NetworkDevice4,
vmConfig.NetworkDevice5,
vmConfig.NetworkDevice6,
vmConfig.NetworkDevice7,
vmConfig.NetworkDevice8,
vmConfig.NetworkDevice9,
vmConfig.NetworkDevice10,
vmConfig.NetworkDevice11,
vmConfig.NetworkDevice12,
vmConfig.NetworkDevice13,
vmConfig.NetworkDevice14,
vmConfig.NetworkDevice15,
vmConfig.NetworkDevice16,
vmConfig.NetworkDevice17,
vmConfig.NetworkDevice18,
vmConfig.NetworkDevice19,
vmConfig.NetworkDevice20,
vmConfig.NetworkDevice21,
vmConfig.NetworkDevice22,
vmConfig.NetworkDevice23,
vmConfig.NetworkDevice24,
vmConfig.NetworkDevice25,
vmConfig.NetworkDevice26,
vmConfig.NetworkDevice27,
vmConfig.NetworkDevice28,
vmConfig.NetworkDevice29,
vmConfig.NetworkDevice30,
vmConfig.NetworkDevice31,
}
for ni, nd := range networkDeviceObjects {
networkDevice := map[string]interface{}{}
if nd != nil {
networkDeviceLast = ni
if nd.Bridge != nil {
networkDevice[mkNetworkDeviceBridge] = *nd.Bridge
} else {
networkDevice[mkNetworkDeviceBridge] = ""
}
networkDevice[mkNetworkDeviceEnabled] = nd.Enabled
if nd.Firewall != nil {
networkDevice[mkNetworkDeviceFirewall] = *nd.Firewall
} else {
networkDevice[mkNetworkDeviceFirewall] = false
}
if nd.MACAddress != nil {
macAddresses[ni] = *nd.MACAddress
} else {
macAddresses[ni] = ""
}
networkDevice[mkNetworkDeviceMACAddress] = macAddresses[ni]
networkDevice[mkNetworkDeviceModel] = nd.Model
if nd.Queues != nil {
networkDevice[mkNetworkDeviceQueues] = *nd.Queues
} else {
networkDevice[mkNetworkDeviceQueues] = 0
}
if nd.RateLimit != nil {
networkDevice[mkNetworkDeviceRateLimit] = *nd.RateLimit
} else {
networkDevice[mkNetworkDeviceRateLimit] = 0
}
if nd.Tag != nil {
networkDevice[mkNetworkDeviceVLANID] = nd.Tag
} else {
networkDevice[mkNetworkDeviceVLANID] = 0
}
if nd.Trunks != nil {
networkDevice[mkNetworkDeviceTrunks] = strings.Trim(
strings.Join(strings.Fields(fmt.Sprint(nd.Trunks)), ";"), "[]")
} else {
networkDevice[mkNetworkDeviceTrunks] = ""
}
if nd.MTU != nil {
networkDevice[mkNetworkDeviceMTU] = nd.MTU
} else {
networkDevice[mkNetworkDeviceMTU] = 0
}
} else {
macAddresses[ni] = ""
networkDevice[mkNetworkDeviceEnabled] = false
}
networkDeviceList[ni] = networkDevice
}
if len(currentNetworkDeviceList) > 0 || networkDeviceLast > -1 {
err := d.Set(MkNetworkDevice, networkDeviceList[:networkDeviceLast+1])
diags = append(diags, diag.FromErr(err)...)
}
err := d.Set(mkMACAddresses, macAddresses[0:len(currentNetworkDeviceList)])
diags = append(diags, diag.FromErr(err)...)
return diags
}
// ReadNetworkValues reads the network values from the resource data.
func ReadNetworkValues(
ctx context.Context,
d *schema.ResourceData,
vmAPI *vms.Client,
started bool,
vmConfig *vms.GetResponseData,
agentTimeout time.Duration,
) diag.Diagnostics {
var diags diag.Diagnostics
var ipv4Addresses []interface{}
var ipv6Addresses []interface{}
var networkInterfaceNames []interface{}
if started {
if vmConfig.Agent != nil && vmConfig.Agent.Enabled != nil && *vmConfig.Agent.Enabled {
var macAddresses []interface{}
networkInterfaces, err := vmAPI.WaitForNetworkInterfacesFromVMAgent(ctx, int(agentTimeout.Seconds()), 5, true)
if err == nil && networkInterfaces.Result != nil {
ipv4Addresses = make([]interface{}, len(*networkInterfaces.Result))
ipv6Addresses = make([]interface{}, len(*networkInterfaces.Result))
macAddresses = make([]interface{}, len(*networkInterfaces.Result))
networkInterfaceNames = make([]interface{}, len(*networkInterfaces.Result))
for ri, rv := range *networkInterfaces.Result {
var rvIPv4Addresses []interface{}
var rvIPv6Addresses []interface{}
if rv.IPAddresses != nil {
for _, ip := range *rv.IPAddresses {
switch ip.Type {
case "ipv4":
rvIPv4Addresses = append(rvIPv4Addresses, ip.Address)
case "ipv6":
rvIPv6Addresses = append(rvIPv6Addresses, ip.Address)
}
}
}
ipv4Addresses[ri] = rvIPv4Addresses
ipv6Addresses[ri] = rvIPv6Addresses
macAddresses[ri] = strings.ToUpper(rv.MACAddress)
networkInterfaceNames[ri] = rv.Name
}
}
err = d.Set(mkMACAddresses, macAddresses)
diags = append(diags, diag.FromErr(err)...)
}
}
e := d.Set(mkIPv4Addresses, ipv4Addresses)
diags = append(diags, diag.FromErr(e)...)
e = d.Set(mkIPv6Addresses, ipv6Addresses)
diags = append(diags, diag.FromErr(e)...)
e = d.Set(mkNetworkInterfaceNames, networkInterfaceNames)
diags = append(diags, diag.FromErr(e)...)
return diags
}

View File

@ -0,0 +1,189 @@
package network
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validators"
)
const (
// MaxNetworkDevices is the maximum number of network devices supported by the resource.
MaxNetworkDevices = 32
dvNetworkDeviceBridge = "vmbr0"
dvNetworkDeviceEnabled = true
dvNetworkDeviceFirewall = false
dvNetworkDeviceModel = "virtio"
dvNetworkDeviceQueues = 0
dvNetworkDeviceRateLimit = 0
dvNetworkDeviceVLANID = 0
dvNetworkDeviceTrunks = ""
dvNetworkDeviceMTU = 0
mkIPv4Addresses = "ipv4_addresses"
mkIPv6Addresses = "ipv6_addresses"
mkMACAddresses = "mac_addresses"
// MkNetworkDevice is the name of the network device.
MkNetworkDevice = "network_device"
mkNetworkDeviceBridge = "bridge"
mkNetworkDeviceEnabled = "enabled"
mkNetworkDeviceFirewall = "firewall"
mkNetworkDeviceMACAddress = "mac_address"
mkNetworkDeviceModel = "model"
mkNetworkDeviceQueues = "queues"
mkNetworkDeviceRateLimit = "rate_limit"
mkNetworkDeviceVLANID = "vlan_id"
mkNetworkDeviceTrunks = "trunks"
mkNetworkDeviceMTU = "mtu"
mkNetworkInterfaceNames = "network_interface_names"
)
// Schema returns the schema for the network resource.
func Schema() map[string]*schema.Schema {
return map[string]*schema.Schema{
mkIPv4Addresses: {
Type: schema.TypeList,
Description: "The IPv4 addresses published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
mkIPv6Addresses: {
Type: schema.TypeList,
Description: "The IPv6 addresses published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
mkMACAddresses: {
Type: schema.TypeList,
Description: "The MAC addresses for the network interfaces",
Computed: true,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
MkNetworkDevice: {
Type: schema.TypeList,
Description: "The network devices",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 1), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkNetworkDeviceBridge: {
Type: schema.TypeString,
Description: "The bridge",
Optional: true,
Default: dvNetworkDeviceBridge,
},
mkNetworkDeviceEnabled: {
Type: schema.TypeBool,
Description: "Whether to enable the network device",
Optional: true,
Default: dvNetworkDeviceEnabled,
},
mkNetworkDeviceFirewall: {
Type: schema.TypeBool,
Description: "Whether this interface's firewall rules should be used",
Optional: true,
Default: dvNetworkDeviceFirewall,
},
mkNetworkDeviceMACAddress: {
Type: schema.TypeString,
Description: "The MAC address",
Optional: true,
Computed: true,
ValidateDiagFunc: validators.MACAddress(),
},
mkNetworkDeviceModel: {
Type: schema.TypeString,
Description: "The model",
Optional: true,
Default: dvNetworkDeviceModel,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
"e1000",
"rtl8139",
"virtio",
"vmxnet3",
}, false)),
},
mkNetworkDeviceQueues: {
Type: schema.TypeInt,
Description: "Number of packet queues to be used on the device",
Optional: true,
Default: dvNetworkDeviceQueues,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntBetween(0, 64)),
},
mkNetworkDeviceRateLimit: {
Type: schema.TypeFloat,
Description: "The rate limit in megabytes per second",
Optional: true,
Default: dvNetworkDeviceRateLimit,
},
mkNetworkDeviceVLANID: {
Type: schema.TypeInt,
Description: "The VLAN identifier",
Optional: true,
Default: dvNetworkDeviceVLANID,
},
mkNetworkDeviceTrunks: {
Type: schema.TypeString,
Optional: true,
Description: "List of VLAN trunks for the network interface",
},
mkNetworkDeviceMTU: {
Type: schema.TypeInt,
Description: "Maximum transmission unit (MTU)",
Optional: true,
Default: dvNetworkDeviceMTU,
},
},
},
MaxItems: MaxNetworkDevices,
MinItems: 0,
},
mkNetworkInterfaceNames: {
Type: schema.TypeList,
Description: "The network interface names published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
}
}
// CustomizeDiff returns the custom diff functions for the network resource.
func CustomizeDiff() []schema.CustomizeDiffFunc {
return []schema.CustomizeDiffFunc{
customdiff.ComputedIf(
mkIPv4Addresses,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange("started") ||
d.HasChange(MkNetworkDevice)
},
),
customdiff.ComputedIf(
mkIPv6Addresses,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange("started") ||
d.HasChange(MkNetworkDevice)
},
),
customdiff.ComputedIf(
mkNetworkInterfaceNames,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange("started") ||
d.HasChange(MkNetworkDevice)
},
),
}
}

View File

@ -0,0 +1,55 @@
package network
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
)
func TestNetworkSchema(t *testing.T) {
t.Parallel()
s := Schema()
test.AssertComputedAttributes(t, s, []string{
mkIPv4Addresses,
mkIPv6Addresses,
mkMACAddresses,
mkNetworkInterfaceNames,
})
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkIPv4Addresses: schema.TypeList,
mkIPv6Addresses: schema.TypeList,
mkMACAddresses: schema.TypeList,
mkNetworkInterfaceNames: schema.TypeList,
})
deviceSchema := test.AssertNestedSchemaExistence(
t,
s,
MkNetworkDevice,
)
test.AssertOptionalArguments(t, deviceSchema, []string{
mkNetworkDeviceBridge,
mkNetworkDeviceEnabled,
mkNetworkDeviceMACAddress,
mkNetworkDeviceModel,
mkNetworkDeviceRateLimit,
mkNetworkDeviceVLANID,
mkNetworkDeviceMTU,
})
test.AssertValueTypes(t, deviceSchema, map[string]schema.ValueType{
mkNetworkDeviceBridge: schema.TypeString,
mkNetworkDeviceEnabled: schema.TypeBool,
mkNetworkDeviceMACAddress: schema.TypeString,
mkNetworkDeviceModel: schema.TypeString,
mkNetworkDeviceRateLimit: schema.TypeFloat,
mkNetworkDeviceVLANID: schema.TypeInt,
mkNetworkDeviceMTU: schema.TypeInt,
})
}

View File

@ -144,11 +144,6 @@ func CPUTypeValidator() schema.SchemaValidateDiagFunc {
))
}
// NetworkDeviceModelValidator is a schema validation function for network device models.
func NetworkDeviceModelValidator() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(validation.StringInSlice([]string{"e1000", "rtl8139", "virtio", "vmxnet3"}, false))
}
// QEMUAgentTypeValidator is a schema validation function for QEMU agent types.
func QEMUAgentTypeValidator() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(validation.StringInSlice([]string{"isa", "virtio"}, false))

View File

@ -17,6 +17,7 @@ import (
"time"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/vm/disk"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/vm/network"
"github.com/bpg/terraform-provider-proxmox/utils"
"github.com/google/go-cmp/cmp"
@ -93,48 +94,39 @@ const (
dvMemoryShared = 0
dvMigrate = false
dvName = ""
dvNetworkDeviceBridge = "vmbr0"
dvNetworkDeviceEnabled = true
dvNetworkDeviceFirewall = false
dvNetworkDeviceModel = "virtio"
dvNetworkDeviceQueues = 0
dvNetworkDeviceRateLimit = 0
dvNetworkDeviceVLANID = 0
dvNetworkDeviceTrunks = ""
dvNetworkDeviceMTU = 0
dvOperatingSystemType = "other"
dvPoolID = ""
dvProtection = false
dvSerialDeviceDevice = "socket"
dvSMBIOSFamily = ""
dvSMBIOSManufacturer = ""
dvSMBIOSProduct = ""
dvSMBIOSSKU = ""
dvSMBIOSSerial = ""
dvSMBIOSVersion = ""
dvStarted = true
dvStartupOrder = -1
dvStartupUpDelay = -1
dvStartupDownDelay = -1
dvTabletDevice = true
dvTemplate = false
dvTimeoutClone = 1800
dvTimeoutCreate = 1800
dvTimeoutMoveDisk = 1800
dvTimeoutMigrate = 1800
dvTimeoutReboot = 1800
dvTimeoutShutdownVM = 1800
dvTimeoutStartVM = 1800
dvTimeoutStopVM = 300
dvVGAEnabled = true
dvVGAMemory = 16
dvVGAType = "std"
dvSCSIHardware = "virtio-scsi-pci"
dvStopOnDestroy = false
dvHookScript = ""
dvOperatingSystemType = "other"
dvPoolID = ""
dvProtection = false
dvSerialDeviceDevice = "socket"
dvSMBIOSFamily = ""
dvSMBIOSManufacturer = ""
dvSMBIOSProduct = ""
dvSMBIOSSKU = ""
dvSMBIOSSerial = ""
dvSMBIOSVersion = ""
dvStarted = true
dvStartupOrder = -1
dvStartupUpDelay = -1
dvStartupDownDelay = -1
dvTabletDevice = true
dvTemplate = false
dvTimeoutClone = 1800
dvTimeoutCreate = 1800
dvTimeoutMoveDisk = 1800
dvTimeoutMigrate = 1800
dvTimeoutReboot = 1800
dvTimeoutShutdownVM = 1800
dvTimeoutStartVM = 1800
dvTimeoutStopVM = 300
dvVGAEnabled = true
dvVGAMemory = 16
dvVGAType = "std"
dvSCSIHardware = "virtio-scsi-pci"
dvStopOnDestroy = false
dvHookScript = ""
maxResourceVirtualEnvironmentVMAudioDevices = 1
maxResourceVirtualEnvironmentVMNetworkDevices = 32
maxResourceVirtualEnvironmentVMSerialDevices = 4
maxResourceVirtualEnvironmentVMHostPCIDevices = 8
maxResourceVirtualEnvironmentVMHostUSBDevices = 4
@ -215,72 +207,59 @@ const (
mkInitializationVendorDataFileID = "vendor_data_file_id"
mkInitializationNetworkDataFileID = "network_data_file_id"
mkInitializationMetaDataFileID = "meta_data_file_id"
mkIPv4Addresses = "ipv4_addresses"
mkIPv6Addresses = "ipv6_addresses"
mkKeyboardLayout = "keyboard_layout"
mkKVMArguments = "kvm_arguments"
mkMachine = "machine"
mkMACAddresses = "mac_addresses"
mkMemory = "memory"
mkMemoryDedicated = "dedicated"
mkMemoryFloating = "floating"
mkMemoryShared = "shared"
mkMigrate = "migrate"
mkName = "name"
mkNetworkDevice = "network_device"
mkNetworkDeviceBridge = "bridge"
mkNetworkDeviceEnabled = "enabled"
mkNetworkDeviceFirewall = "firewall"
mkNetworkDeviceMACAddress = "mac_address"
mkNetworkDeviceModel = "model"
mkNetworkDeviceQueues = "queues"
mkNetworkDeviceRateLimit = "rate_limit"
mkNetworkDeviceVLANID = "vlan_id"
mkNetworkDeviceTrunks = "trunks"
mkNetworkDeviceMTU = "mtu"
mkNetworkInterfaceNames = "network_interface_names"
mkNodeName = "node_name"
mkOperatingSystem = "operating_system"
mkOperatingSystemType = "type"
mkPoolID = "pool_id"
mkProtection = "protection"
mkSerialDevice = "serial_device"
mkSerialDeviceDevice = "device"
mkSMBIOS = "smbios"
mkSMBIOSFamily = "family"
mkSMBIOSManufacturer = "manufacturer"
mkSMBIOSProduct = "product"
mkSMBIOSSKU = "sku"
mkSMBIOSSerial = "serial"
mkSMBIOSUUID = "uuid"
mkSMBIOSVersion = "version"
mkStarted = "started"
mkStartup = "startup"
mkStartupOrder = "order"
mkStartupUpDelay = "up_delay"
mkStartupDownDelay = "down_delay"
mkTabletDevice = "tablet_device"
mkTags = "tags"
mkTemplate = "template"
mkTimeoutClone = "timeout_clone"
mkTimeoutCreate = "timeout_create"
mkTimeoutMigrate = "timeout_migrate"
mkTimeoutReboot = "timeout_reboot"
mkTimeoutShutdownVM = "timeout_shutdown_vm"
mkTimeoutStartVM = "timeout_start_vm"
mkTimeoutStopVM = "timeout_stop_vm"
mkHostUSB = "usb"
mkHostUSBDevice = "host"
mkHostUSBDeviceMapping = "mapping"
mkHostUSBDeviceUSB3 = "usb3"
mkVGA = "vga"
mkVGAEnabled = "enabled"
mkVGAMemory = "memory"
mkVGAType = "type"
mkVMID = "vm_id"
mkSCSIHardware = "scsi_hardware"
mkHookScriptFileID = "hook_script_file_id"
mkStopOnDestroy = "stop_on_destroy"
mkKeyboardLayout = "keyboard_layout"
mkKVMArguments = "kvm_arguments"
mkMachine = "machine"
mkMemory = "memory"
mkMemoryDedicated = "dedicated"
mkMemoryFloating = "floating"
mkMemoryShared = "shared"
mkMigrate = "migrate"
mkName = "name"
mkNodeName = "node_name"
mkOperatingSystem = "operating_system"
mkOperatingSystemType = "type"
mkPoolID = "pool_id"
mkProtection = "protection"
mkSerialDevice = "serial_device"
mkSerialDeviceDevice = "device"
mkSMBIOS = "smbios"
mkSMBIOSFamily = "family"
mkSMBIOSManufacturer = "manufacturer"
mkSMBIOSProduct = "product"
mkSMBIOSSKU = "sku"
mkSMBIOSSerial = "serial"
mkSMBIOSUUID = "uuid"
mkSMBIOSVersion = "version"
mkStarted = "started"
mkStartup = "startup"
mkStartupOrder = "order"
mkStartupUpDelay = "up_delay"
mkStartupDownDelay = "down_delay"
mkTabletDevice = "tablet_device"
mkTags = "tags"
mkTemplate = "template"
mkTimeoutClone = "timeout_clone"
mkTimeoutCreate = "timeout_create"
mkTimeoutMigrate = "timeout_migrate"
mkTimeoutReboot = "timeout_reboot"
mkTimeoutShutdownVM = "timeout_shutdown_vm"
mkTimeoutStartVM = "timeout_start_vm"
mkTimeoutStopVM = "timeout_stop_vm"
mkHostUSB = "usb"
mkHostUSBDevice = "host"
mkHostUSBDeviceMapping = "mapping"
mkHostUSBDeviceUSB3 = "usb3"
mkVGA = "vga"
mkVGAEnabled = "enabled"
mkVGAMemory = "memory"
mkVGAType = "type"
mkVMID = "vm_id"
mkSCSIHardware = "scsi_hardware"
mkHookScriptFileID = "hook_script_file_id"
mkStopOnDestroy = "stop_on_destroy"
)
// VM returns a resource that manages VMs.
@ -897,24 +876,6 @@ func VM() *schema.Resource {
MaxItems: 1,
MinItems: 0,
},
mkIPv4Addresses: {
Type: schema.TypeList,
Description: "The IPv4 addresses published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
mkIPv6Addresses: {
Type: schema.TypeList,
Description: "The IPv6 addresses published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
mkHostPCI: {
Type: schema.TypeList,
Description: "The Host PCI devices mapped to the VM",
@ -1013,13 +974,6 @@ func VM() *schema.Resource {
Default: dvMachineType,
ValidateDiagFunc: MachineTypeValidator(),
},
mkMACAddresses: {
Type: schema.TypeList,
Description: "The MAC addresses for the network interfaces",
Computed: true,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
mkMemory: {
Type: schema.TypeList,
Description: "The memory allocation",
@ -1073,88 +1027,6 @@ func VM() *schema.Resource {
Optional: true,
Default: dvName,
},
mkNetworkDevice: {
Type: schema.TypeList,
Description: "The network devices",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 1), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkNetworkDeviceBridge: {
Type: schema.TypeString,
Description: "The bridge",
Optional: true,
Default: dvNetworkDeviceBridge,
},
mkNetworkDeviceEnabled: {
Type: schema.TypeBool,
Description: "Whether to enable the network device",
Optional: true,
Default: dvNetworkDeviceEnabled,
},
mkNetworkDeviceFirewall: {
Type: schema.TypeBool,
Description: "Whether this interface's firewall rules should be used",
Optional: true,
Default: dvNetworkDeviceFirewall,
},
mkNetworkDeviceMACAddress: {
Type: schema.TypeString,
Description: "The MAC address",
Optional: true,
Computed: true,
ValidateDiagFunc: validators.MACAddress(),
},
mkNetworkDeviceModel: {
Type: schema.TypeString,
Description: "The model",
Optional: true,
Default: dvNetworkDeviceModel,
ValidateDiagFunc: NetworkDeviceModelValidator(),
},
mkNetworkDeviceQueues: {
Type: schema.TypeInt,
Description: "Number of packet queues to be used on the device",
Optional: true,
Default: dvNetworkDeviceQueues,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntBetween(0, 64)),
},
mkNetworkDeviceRateLimit: {
Type: schema.TypeFloat,
Description: "The rate limit in megabytes per second",
Optional: true,
Default: dvNetworkDeviceRateLimit,
},
mkNetworkDeviceVLANID: {
Type: schema.TypeInt,
Description: "The VLAN identifier",
Optional: true,
Default: dvNetworkDeviceVLANID,
},
mkNetworkDeviceTrunks: {
Type: schema.TypeString,
Optional: true,
Description: "List of VLAN trunks for the network interface",
},
mkNetworkDeviceMTU: {
Type: schema.TypeInt,
Description: "Maximum transmission unit (MTU)",
Optional: true,
Default: dvNetworkDeviceMTU,
},
},
},
MaxItems: maxResourceVirtualEnvironmentVMNetworkDevices,
MinItems: 0,
},
mkNetworkInterfaceNames: {
Type: schema.TypeList,
Description: "The network interface names published by the QEMU agent",
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
mkNodeName: {
Type: schema.TypeString,
Description: "The node name",
@ -1462,6 +1334,7 @@ func VM() *schema.Resource {
}
structure.MergeSchema(s, disk.Schema())
structure.MergeSchema(s, network.Schema())
return &schema.Resource{
Schema: s,
@ -1470,27 +1343,7 @@ func VM() *schema.Resource {
UpdateContext: vmUpdate,
DeleteContext: vmDelete,
CustomizeDiff: customdiff.All(
customdiff.ComputedIf(
mkIPv4Addresses,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange(mkStarted) ||
d.HasChange(mkNetworkDevice)
},
),
customdiff.ComputedIf(
mkIPv6Addresses,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange(mkStarted) ||
d.HasChange(mkNetworkDevice)
},
),
customdiff.ComputedIf(
mkNetworkInterfaceNames,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
return d.HasChange(mkStarted) ||
d.HasChange(mkNetworkDevice)
},
),
customdiff.All(network.CustomizeDiff()...),
customdiff.ForceNewIf(
mkVMID,
func(_ context.Context, d *schema.ResourceDiff, _ interface{}) bool {
@ -1825,7 +1678,6 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
hostUSB := d.Get(mkHostUSB).([]interface{})
keyboardLayout := d.Get(mkKeyboardLayout).(string)
memory := d.Get(mkMemory).([]interface{})
networkDevice := d.Get(mkNetworkDevice).([]interface{})
operatingSystem := d.Get(mkOperatingSystem).([]interface{})
serialDevice := d.Get(mkSerialDevice).([]interface{})
onBoot := types.CustomBool(d.Get(mkOnBoot).(bool))
@ -2027,8 +1879,9 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
}
}
networkDevice := d.Get(network.MkNetworkDevice).([]interface{})
if len(networkDevice) > 0 {
updateBody.NetworkDevices, err = vmGetNetworkDeviceObjects(d)
updateBody.NetworkDevices, err = network.GetNetworkDeviceObjects(d)
if err != nil {
return diag.FromErr(err)
}
@ -2039,7 +1892,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
}
}
for i := len(updateBody.NetworkDevices); i < maxResourceVirtualEnvironmentVMNetworkDevices; i++ {
for i := len(updateBody.NetworkDevices); i < network.MaxNetworkDevices; i++ {
del = append(del, fmt.Sprintf("net%d", i))
}
}
@ -2426,7 +2279,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
name := d.Get(mkName).(string)
tags := d.Get(mkTags).([]interface{})
networkDeviceObjects, err := vmGetNetworkDeviceObjects(d)
networkDeviceObjects, err := network.GetNetworkDeviceObjects(d)
if err != nil {
return diag.FromErr(err)
}
@ -3054,77 +2907,6 @@ func vmGetHostUSBDeviceObjects(d *schema.ResourceData) vms.CustomUSBDevices {
return usbDeviceObjects
}
func vmGetNetworkDeviceObjects(d *schema.ResourceData) (vms.CustomNetworkDevices, error) {
networkDevice := d.Get(mkNetworkDevice).([]interface{})
networkDeviceObjects := make(vms.CustomNetworkDevices, len(networkDevice))
for i, networkDeviceEntry := range networkDevice {
block := networkDeviceEntry.(map[string]interface{})
bridge := block[mkNetworkDeviceBridge].(string)
enabled := block[mkNetworkDeviceEnabled].(bool)
firewall := types.CustomBool(block[mkNetworkDeviceFirewall].(bool))
macAddress := block[mkNetworkDeviceMACAddress].(string)
model := block[mkNetworkDeviceModel].(string)
queues := block[mkNetworkDeviceQueues].(int)
rateLimit := block[mkNetworkDeviceRateLimit].(float64)
vlanID := block[mkNetworkDeviceVLANID].(int)
trunks := block[mkNetworkDeviceTrunks].(string)
mtu := block[mkNetworkDeviceMTU].(int)
device := vms.CustomNetworkDevice{
Enabled: enabled,
Firewall: &firewall,
Model: model,
}
if bridge != "" {
device.Bridge = &bridge
}
if macAddress != "" {
device.MACAddress = &macAddress
}
if queues != 0 {
device.Queues = &queues
}
if rateLimit != 0 {
device.RateLimit = &rateLimit
}
if vlanID != 0 {
device.Tag = &vlanID
}
if trunks != "" {
splitTrunks := strings.Split(trunks, ";")
var trunksAsInt []int
for _, numStr := range splitTrunks {
num, err := strconv.Atoi(numStr)
if err != nil {
return nil, fmt.Errorf("error parsing trunks: %w", err)
}
trunksAsInt = append(trunksAsInt, num)
}
device.Trunks = trunksAsInt
}
if mtu != 0 {
device.MTU = &mtu
}
networkDeviceObjects[i] = device
}
return networkDeviceObjects, nil
}
func vmGetSerialDeviceList(d *schema.ResourceData) vms.CustomSerialDevices {
device := d.Get(mkSerialDevice).([]interface{})
list := make(vms.CustomSerialDevices, len(device))
@ -3350,9 +3132,9 @@ func vmReadCustom(
) diag.Diagnostics {
config := m.(proxmoxtf.ProviderConfiguration)
api, err := config.GetClient()
if err != nil {
return diag.FromErr(err)
api, e := config.GetClient()
if e != nil {
return diag.FromErr(e)
}
diags := vmReadPrimitiveValues(d, vmConfig, vmStatus)
@ -3368,7 +3150,7 @@ func vmReadCustom(
d.Id(), storedVMID, vmID),
})
err = d.Set(mkVMID, vmID)
err := d.Set(mkVMID, vmID)
diags = append(diags, diag.FromErr(err)...)
}
@ -3418,7 +3200,7 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentAgent) > 0 {
err = d.Set(mkAgent, []interface{}{agent})
err := d.Set(mkAgent, []interface{}{agent})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentAgent) > 0 ||
@ -3426,16 +3208,16 @@ func vmReadCustom(
agent[mkAgentTimeout] != dvAgentTimeout ||
agent[mkAgentTrim] != dvAgentTrim ||
agent[mkAgentType] != dvAgentType {
err = d.Set(mkAgent, []interface{}{agent})
err := d.Set(mkAgent, []interface{}{agent})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(clone) > 0 {
if len(currentAgent) > 0 {
err = d.Set(mkAgent, []interface{}{})
err := d.Set(mkAgent, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}
} else {
err = d.Set(mkAgent, []interface{}{})
err := d.Set(mkAgent, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}
}
@ -3474,7 +3256,7 @@ func vmReadCustom(
}
if len(clone) == 0 || len(currentAudioDevice) > 0 {
err = d.Set(mkAudioDevice, audioDevices[:audioDevicesCount])
err := d.Set(mkAudioDevice, audioDevices[:audioDevicesCount])
diags = append(diags, diag.FromErr(err)...)
}
@ -3512,11 +3294,11 @@ func vmReadCustom(
cdrom[0] = cdromBlock
err = d.Set(mkCDROM, cdrom)
err := d.Set(mkCDROM, cdrom)
diags = append(diags, diag.FromErr(err)...)
}
} else {
err = d.Set(mkCDROM, []interface{}{})
err := d.Set(mkCDROM, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}
@ -3601,7 +3383,7 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentCPU) > 0 {
err = d.Set(mkCPU, []interface{}{cpu})
err := d.Set(mkCPU, []interface{}{cpu})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentCPU) > 0 ||
@ -3613,7 +3395,7 @@ func vmReadCustom(
cpu[mkCPUSockets] != dvCPUSockets ||
cpu[mkCPUType] != dvCPUType ||
cpu[mkCPUUnits] != dvCPUUnits {
err = d.Set(mkCPU, []interface{}{cpu})
err := d.Set(mkCPU, []interface{}{cpu})
diags = append(diags, diag.FromErr(err)...)
}
@ -3636,8 +3418,8 @@ func vmReadCustom(
} else {
// disk format may not be returned by config API if it is default for the storage, and that may be different
// from the default qcow2, so we need to read it from the storage API to make sure we have the correct value
volume, e := api.Node(nodeName).Storage(fileIDParts[0]).GetDatastoreFile(ctx, vmConfig.EFIDisk.FileVolume)
if e != nil {
volume, err := api.Node(nodeName).Storage(fileIDParts[0]).GetDatastoreFile(ctx, vmConfig.EFIDisk.FileVolume)
if err != nil {
diags = append(diags, diag.FromErr(e)...)
} else {
efiDisk[mkEFIDiskFileFormat] = volume.FileFormat
@ -3660,7 +3442,7 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentEfiDisk) > 0 {
err = d.Set(mkEFIDisk, []interface{}{efiDisk})
err := d.Set(mkEFIDisk, []interface{}{efiDisk})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentEfiDisk) > 0 ||
@ -3668,7 +3450,7 @@ func vmReadCustom(
efiDisk[mkEFIDiskType] != dvEFIDiskType ||
efiDisk[mkEFIDiskPreEnrolledKeys] != dvEFIDiskPreEnrolledKeys ||
efiDisk[mkEFIDiskFileFormat] != dvEFIDiskFileFormat {
err = d.Set(mkEFIDisk, []interface{}{efiDisk})
err := d.Set(mkEFIDisk, []interface{}{efiDisk})
diags = append(diags, diag.FromErr(err)...)
}
}
@ -3685,13 +3467,13 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentTPMState) > 0 {
err = d.Set(mkTPMState, []interface{}{tpmState})
err := d.Set(mkTPMState, []interface{}{tpmState})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentTPMState) > 0 ||
tpmState[mkTPMStateDatastoreID] != dvTPMStateDatastoreID ||
tpmState[mkTPMStateVersion] != dvTPMStateVersion {
err = d.Set(mkTPMState, []interface{}{tpmState})
err := d.Set(mkTPMState, []interface{}{tpmState})
diags = append(diags, diag.FromErr(err)...)
}
}
@ -3755,7 +3537,7 @@ func vmReadCustom(
if len(clone) == 0 || len(currentPCIList) > 0 {
orderedPCIList := utils.OrderedListFromMap(pciMap)
err = d.Set(mkHostPCI, orderedPCIList)
err := d.Set(mkHostPCI, orderedPCIList)
diags = append(diags, diag.FromErr(err)...)
}
@ -3794,7 +3576,7 @@ func vmReadCustom(
if len(clone) == 0 || len(currentUSBList) > 0 {
// NOTE: reordering of devices by PVE may cause an issue here
orderedUSBList := utils.OrderedListFromMap(usbMap)
err = d.Set(mkHostUSB, orderedUSBList)
err := d.Set(mkHostUSB, orderedUSBList)
diags = append(diags, diag.FromErr(err)...)
}
@ -4022,18 +3804,18 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentInitialization) > 0 {
if len(initialization) > 0 {
err = d.Set(mkInitialization, []interface{}{initialization})
err := d.Set(mkInitialization, []interface{}{initialization})
diags = append(diags, diag.FromErr(err)...)
} else {
err = d.Set(mkInitialization, []interface{}{})
err := d.Set(mkInitialization, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}
}
} else if len(initialization) > 0 {
err = d.Set(mkInitialization, []interface{}{initialization})
err := d.Set(mkInitialization, []interface{}{initialization})
diags = append(diags, diag.FromErr(err)...)
} else {
err = d.Set(mkInitialization, []interface{}{})
err := d.Set(mkInitialization, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}
@ -4071,132 +3853,18 @@ func vmReadCustom(
if len(clone) > 0 {
if len(currentMemory) > 0 {
err = d.Set(mkMemory, []interface{}{memory})
err := d.Set(mkMemory, []interface{}{memory})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentMemory) > 0 ||
memory[mkMemoryDedicated] != dvMemoryDedicated ||
memory[mkMemoryFloating] != dvMemoryFloating ||
memory[mkMemoryShared] != dvMemoryShared {
err = d.Set(mkMemory, []interface{}{memory})
err := d.Set(mkMemory, []interface{}{memory})
diags = append(diags, diag.FromErr(err)...)
}
// Compare the network devices to those stored in the state.
currentNetworkDeviceList := d.Get(mkNetworkDevice).([]interface{})
macAddresses := make([]interface{}, maxResourceVirtualEnvironmentVMNetworkDevices)
networkDeviceLast := -1
networkDeviceList := make([]interface{}, maxResourceVirtualEnvironmentVMNetworkDevices)
networkDeviceObjects := []*vms.CustomNetworkDevice{
vmConfig.NetworkDevice0,
vmConfig.NetworkDevice1,
vmConfig.NetworkDevice2,
vmConfig.NetworkDevice3,
vmConfig.NetworkDevice4,
vmConfig.NetworkDevice5,
vmConfig.NetworkDevice6,
vmConfig.NetworkDevice7,
vmConfig.NetworkDevice8,
vmConfig.NetworkDevice9,
vmConfig.NetworkDevice10,
vmConfig.NetworkDevice11,
vmConfig.NetworkDevice12,
vmConfig.NetworkDevice13,
vmConfig.NetworkDevice14,
vmConfig.NetworkDevice15,
vmConfig.NetworkDevice16,
vmConfig.NetworkDevice17,
vmConfig.NetworkDevice18,
vmConfig.NetworkDevice19,
vmConfig.NetworkDevice20,
vmConfig.NetworkDevice21,
vmConfig.NetworkDevice22,
vmConfig.NetworkDevice23,
vmConfig.NetworkDevice24,
vmConfig.NetworkDevice25,
vmConfig.NetworkDevice26,
vmConfig.NetworkDevice27,
vmConfig.NetworkDevice28,
vmConfig.NetworkDevice29,
vmConfig.NetworkDevice30,
vmConfig.NetworkDevice31,
}
for ni, nd := range networkDeviceObjects {
networkDevice := map[string]interface{}{}
if nd != nil {
networkDeviceLast = ni
if nd.Bridge != nil {
networkDevice[mkNetworkDeviceBridge] = *nd.Bridge
} else {
networkDevice[mkNetworkDeviceBridge] = ""
}
networkDevice[mkNetworkDeviceEnabled] = nd.Enabled
if nd.Firewall != nil {
networkDevice[mkNetworkDeviceFirewall] = *nd.Firewall
} else {
networkDevice[mkNetworkDeviceFirewall] = false
}
if nd.MACAddress != nil {
macAddresses[ni] = *nd.MACAddress
} else {
macAddresses[ni] = ""
}
networkDevice[mkNetworkDeviceMACAddress] = macAddresses[ni]
networkDevice[mkNetworkDeviceModel] = nd.Model
if nd.Queues != nil {
networkDevice[mkNetworkDeviceQueues] = *nd.Queues
} else {
networkDevice[mkNetworkDeviceQueues] = 0
}
if nd.RateLimit != nil {
networkDevice[mkNetworkDeviceRateLimit] = *nd.RateLimit
} else {
networkDevice[mkNetworkDeviceRateLimit] = 0
}
if nd.Tag != nil {
networkDevice[mkNetworkDeviceVLANID] = nd.Tag
} else {
networkDevice[mkNetworkDeviceVLANID] = 0
}
if nd.Trunks != nil {
networkDevice[mkNetworkDeviceTrunks] = strings.Trim(
strings.Join(strings.Fields(fmt.Sprint(nd.Trunks)), ";"), "[]")
} else {
networkDevice[mkNetworkDeviceTrunks] = ""
}
if nd.MTU != nil {
networkDevice[mkNetworkDeviceMTU] = nd.MTU
} else {
networkDevice[mkNetworkDeviceMTU] = 0
}
} else {
macAddresses[ni] = ""
networkDevice[mkNetworkDeviceEnabled] = false
}
networkDeviceList[ni] = networkDevice
}
err = d.Set(mkMACAddresses, macAddresses[0:len(currentNetworkDeviceList)])
diags = append(diags, diag.FromErr(err)...)
if len(currentNetworkDeviceList) > 0 || networkDeviceLast > -1 {
err := d.Set(mkNetworkDevice, networkDeviceList[:networkDeviceLast+1])
diags = append(diags, diag.FromErr(err)...)
}
diags = append(diags, network.ReadNetworkDeviceObjects(d, vmConfig)...)
// Compare the operating system configuration to the one stored in the state.
operatingSystem := map[string]interface{}{}
@ -4455,112 +4123,23 @@ func vmReadCustom(
}
}
diags = append(
diags,
vmReadNetworkValues(ctx, d, m, vmID, vmConfig)...)
vmAPI := api.Node(nodeName).VM(vmID)
started := d.Get(mkStarted).(bool)
// during import these core attributes might not be set, so set them explicitly here
d.SetId(strconv.Itoa(vmID))
e := d.Set(mkVMID, vmID)
diags = append(diags, diag.FromErr(e)...)
e = d.Set(mkNodeName, nodeName)
diags = append(diags, diag.FromErr(e)...)
return diags
}
func vmReadNetworkValues(
ctx context.Context,
d *schema.ResourceData,
m interface{},
vmID int,
vmConfig *vms.GetResponseData,
) diag.Diagnostics {
var diags diag.Diagnostics
config := m.(proxmoxtf.ProviderConfiguration)
api, e := config.GetClient()
agentTimeout, e := getAgentTimeout(d)
if e != nil {
return diag.FromErr(e)
}
nodeName := d.Get(mkNodeName).(string)
diags = append(
diags,
network.ReadNetworkValues(ctx, d, vmAPI, started, vmConfig, agentTimeout)...)
vmAPI := api.Node(nodeName).VM(vmID)
started := d.Get(mkStarted).(bool)
var ipv4Addresses []interface{}
var ipv6Addresses []interface{}
var networkInterfaceNames []interface{}
if started {
if vmConfig.Agent != nil && vmConfig.Agent.Enabled != nil && *vmConfig.Agent.Enabled {
resource := VM()
agentBlock, err := structure.GetSchemaBlock(
resource,
d,
[]string{mkAgent},
0,
true,
)
if err != nil {
return diag.FromErr(err)
}
agentTimeout, err := time.ParseDuration(
agentBlock[mkAgentTimeout].(string),
)
if err != nil {
return diag.FromErr(err)
}
var macAddresses []interface{}
networkInterfaces, err := vmAPI.WaitForNetworkInterfacesFromVMAgent(ctx, int(agentTimeout.Seconds()), 5, true)
if err == nil && networkInterfaces.Result != nil {
ipv4Addresses = make([]interface{}, len(*networkInterfaces.Result))
ipv6Addresses = make([]interface{}, len(*networkInterfaces.Result))
macAddresses = make([]interface{}, len(*networkInterfaces.Result))
networkInterfaceNames = make([]interface{}, len(*networkInterfaces.Result))
for ri, rv := range *networkInterfaces.Result {
var rvIPv4Addresses []interface{}
var rvIPv6Addresses []interface{}
if rv.IPAddresses != nil {
for _, ip := range *rv.IPAddresses {
switch ip.Type {
case "ipv4":
rvIPv4Addresses = append(rvIPv4Addresses, ip.Address)
case "ipv6":
rvIPv6Addresses = append(rvIPv6Addresses, ip.Address)
}
}
}
ipv4Addresses[ri] = rvIPv4Addresses
ipv6Addresses[ri] = rvIPv6Addresses
macAddresses[ri] = strings.ToUpper(rv.MACAddress)
networkInterfaceNames[ri] = rv.Name
}
}
err = d.Set(mkMACAddresses, macAddresses)
diags = append(diags, diag.FromErr(err)...)
}
}
e = d.Set(mkIPv4Addresses, ipv4Addresses)
// during import these core attributes might not be set, so set them explicitly here
d.SetId(strconv.Itoa(vmID))
e = d.Set(mkVMID, vmID)
diags = append(diags, diag.FromErr(e)...)
e = d.Set(mkIPv6Addresses, ipv6Addresses)
diags = append(diags, diag.FromErr(e)...)
e = d.Set(mkNetworkInterfaceNames, networkInterfaceNames)
e = d.Set(mkNodeName, nodeName)
diags = append(diags, diag.FromErr(e)...)
return diags
@ -5257,8 +4836,9 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
}
// Prepare the new network device configuration.
if d.HasChange(mkNetworkDevice) {
updateBody.NetworkDevices, err = vmGetNetworkDeviceObjects(d)
if d.HasChange(network.MkNetworkDevice) {
updateBody.NetworkDevices, err = network.GetNetworkDeviceObjects(d)
if err != nil {
return diag.FromErr(err)
}
@ -5269,7 +4849,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
}
}
for i := len(updateBody.NetworkDevices); i < maxResourceVirtualEnvironmentVMNetworkDevices; i++ {
for i := len(updateBody.NetworkDevices); i < network.MaxNetworkDevices; i++ {
del = append(del, fmt.Sprintf("net%d", i))
}
@ -5731,3 +5311,27 @@ func parseImportIDWithNodeName(id string) (string, string, error) {
return nodeName, id, nil
}
func getAgentTimeout(d *schema.ResourceData) (time.Duration, error) {
resource := VM()
agentBlock, err := structure.GetSchemaBlock(
resource,
d,
[]string{mkAgent},
0,
true,
)
if err != nil {
return 0, fmt.Errorf("failed to get agent block: %w", err)
}
agentTimeout, err := time.ParseDuration(
agentBlock[mkAgentTimeout].(string),
)
if err != nil {
return 0, fmt.Errorf("failed to parse agent timeout: %w", err)
}
return agentTimeout, nil
}

View File

@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/vm/disk"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/vm/network"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
)
@ -20,8 +21,8 @@ import (
func TestVMInstantiation(t *testing.T) {
t.Parallel()
s := VM()
if s == nil {
r := VM()
if r == nil {
t.Fatalf("Cannot instantiate VM")
}
}
@ -30,7 +31,7 @@ func TestVMInstantiation(t *testing.T) {
func TestVMSchema(t *testing.T) {
t.Parallel()
s := VM()
s := VM().Schema
test.AssertRequiredArguments(t, s, []string{
mkNodeName,
@ -56,7 +57,7 @@ func TestVMSchema(t *testing.T) {
mkMachine,
mkMemory,
mkName,
mkNetworkDevice,
network.MkNetworkDevice,
mkOperatingSystem,
mkPoolID,
mkSerialDevice,
@ -67,45 +68,33 @@ func TestVMSchema(t *testing.T) {
mkSCSIHardware,
})
test.AssertComputedAttributes(t, s, []string{
mkIPv4Addresses,
mkIPv6Addresses,
mkMACAddresses,
mkNetworkInterfaceNames,
})
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkACPI: schema.TypeBool,
mkAgent: schema.TypeList,
mkAudioDevice: schema.TypeList,
mkBIOS: schema.TypeString,
mkBootOrder: schema.TypeList,
mkCDROM: schema.TypeList,
mkCPU: schema.TypeList,
mkDescription: schema.TypeString,
disk.MkDisk: schema.TypeList,
mkEFIDisk: schema.TypeList,
mkHostPCI: schema.TypeList,
mkHostUSB: schema.TypeList,
mkInitialization: schema.TypeList,
mkIPv4Addresses: schema.TypeList,
mkIPv6Addresses: schema.TypeList,
mkKeyboardLayout: schema.TypeString,
mkKVMArguments: schema.TypeString,
mkMachine: schema.TypeString,
mkMemory: schema.TypeList,
mkName: schema.TypeString,
mkNetworkDevice: schema.TypeList,
mkMACAddresses: schema.TypeList,
mkNetworkInterfaceNames: schema.TypeList,
mkOperatingSystem: schema.TypeList,
mkPoolID: schema.TypeString,
mkSerialDevice: schema.TypeList,
mkStarted: schema.TypeBool,
mkTabletDevice: schema.TypeBool,
mkTemplate: schema.TypeBool,
mkVMID: schema.TypeInt,
mkSCSIHardware: schema.TypeString,
mkACPI: schema.TypeBool,
mkAgent: schema.TypeList,
mkAudioDevice: schema.TypeList,
mkBIOS: schema.TypeString,
mkBootOrder: schema.TypeList,
mkCDROM: schema.TypeList,
mkCPU: schema.TypeList,
mkDescription: schema.TypeString,
disk.MkDisk: schema.TypeList,
mkEFIDisk: schema.TypeList,
mkHostPCI: schema.TypeList,
mkHostUSB: schema.TypeList,
mkInitialization: schema.TypeList,
mkKeyboardLayout: schema.TypeString,
mkKVMArguments: schema.TypeString,
mkMachine: schema.TypeString,
mkMemory: schema.TypeList,
mkName: schema.TypeString,
mkOperatingSystem: schema.TypeList,
mkPoolID: schema.TypeString,
mkSerialDevice: schema.TypeList,
mkStarted: schema.TypeBool,
mkTabletDevice: schema.TypeBool,
mkTemplate: schema.TypeBool,
mkVMID: schema.TypeInt,
mkSCSIHardware: schema.TypeString,
})
agentSchema := test.AssertNestedSchemaExistence(t, s, mkAgent)
@ -188,44 +177,6 @@ func TestVMSchema(t *testing.T) {
mkCPUUnits: schema.TypeInt,
})
// diskSchema := test.AssertNestedSchemaExistence(t, s, mkDisk)
//
// test.AssertOptionalArguments(t, diskSchema, []string{
// mkDiskDatastoreID,
// mkDiskPathInDatastore,
// mkDiskFileFormat,
// mkDiskFileID,
// mkDiskSize,
// })
//
// test.AssertValueTypes(t, diskSchema, map[string]schema.ValueType{
// mkDiskDatastoreID: schema.TypeString,
// mkDiskPathInDatastore: schema.TypeString,
// mkDiskFileFormat: schema.TypeString,
// mkDiskFileID: schema.TypeString,
// mkDiskSize: schema.TypeInt,
// })
//
// diskSpeedSchema := test.AssertNestedSchemaExistence(
// t,
// diskSchema,
// mkDiskSpeed,
//)
//
// test.AssertOptionalArguments(t, diskSpeedSchema, []string{
// mkDiskSpeedRead,
// mkDiskSpeedReadBurstable,
// mkDiskSpeedWrite,
// mkDiskSpeedWriteBurstable,
// })
//
// test.AssertValueTypes(t, diskSpeedSchema, map[string]schema.ValueType{
// mkDiskSpeedRead: schema.TypeInt,
// mkDiskSpeedReadBurstable: schema.TypeInt,
// mkDiskSpeedWrite: schema.TypeInt,
// mkDiskSpeedWriteBurstable: schema.TypeInt,
// })
efiDiskSchema := test.AssertNestedSchemaExistence(t, s, mkEFIDisk)
test.AssertOptionalArguments(t, efiDiskSchema, []string{
@ -390,32 +341,6 @@ func TestVMSchema(t *testing.T) {
mkMemoryShared: schema.TypeInt,
})
networkDeviceSchema := test.AssertNestedSchemaExistence(
t,
s,
mkNetworkDevice,
)
test.AssertOptionalArguments(t, networkDeviceSchema, []string{
mkNetworkDeviceBridge,
mkNetworkDeviceEnabled,
mkNetworkDeviceMACAddress,
mkNetworkDeviceModel,
mkNetworkDeviceRateLimit,
mkNetworkDeviceVLANID,
mkNetworkDeviceMTU,
})
test.AssertValueTypes(t, networkDeviceSchema, map[string]schema.ValueType{
mkNetworkDeviceBridge: schema.TypeString,
mkNetworkDeviceEnabled: schema.TypeBool,
mkNetworkDeviceMACAddress: schema.TypeString,
mkNetworkDeviceModel: schema.TypeString,
mkNetworkDeviceRateLimit: schema.TypeFloat,
mkNetworkDeviceVLANID: schema.TypeInt,
mkNetworkDeviceMTU: schema.TypeInt,
})
operatingSystemSchema := test.AssertNestedSchemaExistence(
t,
s,

View File

@ -15,20 +15,20 @@ import (
)
// AssertComputedAttributes checks that the given schema has the given computed attributes.
func AssertComputedAttributes(t *testing.T, s *schema.Resource, keys []string) {
func AssertComputedAttributes(t *testing.T, s map[string]*schema.Schema, keys []string) {
t.Helper()
for _, v := range keys {
require.NotNil(t, s.Schema[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s.Schema[v].Computed, "Error in Schema: Attribute \"%s\" is not computed", v)
require.NotNil(t, s[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s[v].Computed, "Error in Schema: Attribute \"%s\" is not computed", v)
}
}
// AssertNestedSchemaExistence checks that the given schema has a nested schema for the given key.
func AssertNestedSchemaExistence(t *testing.T, s *schema.Resource, key string) *schema.Resource {
func AssertNestedSchemaExistence(t *testing.T, s map[string]*schema.Schema, key string) map[string]*schema.Schema {
t.Helper()
sh, ok := s.Schema[key].Elem.(*schema.Resource)
r, ok := s[key].Elem.(*schema.Resource)
if !ok {
t.Fatalf("Error in Schema: Missing nested schema for \"%s\"", key)
@ -36,45 +36,45 @@ func AssertNestedSchemaExistence(t *testing.T, s *schema.Resource, key string) *
return nil
}
return sh
return r.Schema
}
// AssertListMaxItems checks that the given schema attribute has given expected MaxItems value.
func AssertListMaxItems(t *testing.T, s *schema.Resource, key string, expectedMaxItems int) {
func AssertListMaxItems(t *testing.T, s map[string]*schema.Schema, key string, expectedMaxItems int) {
t.Helper()
require.NotNil(t, s.Schema[key], "Error in Schema: Missing definition for \"%s\"", key)
assert.Equal(t, expectedMaxItems, s.Schema[key].MaxItems,
require.NotNil(t, s[key], "Error in Schema: Missing definition for \"%s\"", key)
assert.Equal(t, expectedMaxItems, s[key].MaxItems,
"Error in Schema: Argument \"%s\" has \"MaxItems: %#v\", but value %#v is expected!",
key, s.Schema[key].MaxItems, expectedMaxItems)
key, s[key].MaxItems, expectedMaxItems)
}
// AssertOptionalArguments checks that the given schema has the given optional arguments.
func AssertOptionalArguments(t *testing.T, s *schema.Resource, keys []string) {
func AssertOptionalArguments(t *testing.T, s map[string]*schema.Schema, keys []string) {
t.Helper()
for _, v := range keys {
require.NotNil(t, s.Schema[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s.Schema[v].Optional, "Error in Schema: Argument \"%s\" is not optional", v)
require.NotNil(t, s[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s[v].Optional, "Error in Schema: Argument \"%s\" is not optional", v)
}
}
// AssertRequiredArguments checks that the given schema has the given required arguments.
func AssertRequiredArguments(t *testing.T, s *schema.Resource, keys []string) {
func AssertRequiredArguments(t *testing.T, s map[string]*schema.Schema, keys []string) {
t.Helper()
for _, v := range keys {
require.NotNil(t, s.Schema[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s.Schema[v].Required, "Error in Schema: Argument \"%s\" is not required", v)
require.NotNil(t, s[v], "Error in Schema: Missing definition for \"%s\"", v)
assert.True(t, s[v].Required, "Error in Schema: Argument \"%s\" is not required", v)
}
}
// AssertValueTypes checks that the given schema has the given value types for the given fields.
func AssertValueTypes(t *testing.T, s *schema.Resource, f map[string]schema.ValueType) {
func AssertValueTypes(t *testing.T, s map[string]*schema.Schema, f map[string]schema.ValueType) {
t.Helper()
for fn, ft := range f {
require.NotNil(t, s.Schema[fn], "Error in Schema: Missing definition for \"%s\"", fn)
assert.Equal(t, ft, s.Schema[fn].Type, "Error in Schema: Argument or attribute \"%s\" is not of type \"%v\"", fn, ft)
require.NotNil(t, s[fn], "Error in Schema: Missing definition for \"%s\"", fn)
assert.Equal(t, ft, s[fn].Type, "Error in Schema: Argument or attribute \"%s\" is not of type \"%v\"", fn, ft)
}
}