mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-08-24 04:18:33 +00:00
chore: cleanup resource validators & utility code (#438)
* chore: cleanup resource validators & utility code * fix linter errors
This commit is contained in:
parent
6781c03ca1
commit
b2a27f3ccf
2
Makefile
2
Makefile
@ -72,7 +72,7 @@ init:
|
||||
go get ./...
|
||||
|
||||
test:
|
||||
go test -v ./...
|
||||
go test ./...
|
||||
|
||||
lint:
|
||||
go run -modfile=tools/go.mod github.com/golangci/golangci-lint/cmd/golangci-lint run --fix
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestAliasSchemaInstantiation tests whether the AliasSchema instance can be instantiated.
|
||||
@ -25,18 +25,18 @@ func TestAliasSchemaInstantiation(t *testing.T) {
|
||||
func TestAliasSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := AliasSchema()
|
||||
r := schema.Resource{Schema: AliasSchema()}
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, &r, []string{
|
||||
mkAliasName,
|
||||
})
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkAliasCIDR,
|
||||
mkAliasComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkAliasName: schema.TypeString,
|
||||
mkAliasCIDR: schema.TypeString,
|
||||
mkAliasComment: schema.TypeString,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestAliasesSchemaInstantiation tests whether the AliasesSchema instance can be instantiated.
|
||||
@ -25,13 +25,13 @@ func TestAliasesSchemaInstantiation(t *testing.T) {
|
||||
func TestAliasesSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := AliasesSchema()
|
||||
r := schema.Resource{Schema: AliasesSchema()}
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkAliasesAliasNames,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkAliasesAliasNames: schema.TypeList,
|
||||
})
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestIPSetSchemaInstantiation tests whether the IPSetSchema instance can be instantiated.
|
||||
@ -25,32 +25,32 @@ func TestIPSetSchemaInstantiation(t *testing.T) {
|
||||
func TestIPSetSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := IPSetSchema()
|
||||
r := schema.Resource{Schema: IPSetSchema()}
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, &r, []string{
|
||||
mkIPSetName,
|
||||
})
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkIPSetCIDR,
|
||||
mkIPSetCIDRComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkIPSetName: schema.TypeString,
|
||||
mkIPSetCIDR: schema.TypeList,
|
||||
mkIPSetCIDRComment: schema.TypeString,
|
||||
})
|
||||
|
||||
cirdSchema := structure.AssertNestedSchemaExistence(t, s, mkIPSetCIDR).Schema
|
||||
cird := test.AssertNestedSchemaExistence(t, &r, mkIPSetCIDR)
|
||||
|
||||
structure.AssertComputedAttributes(t, cirdSchema, []string{
|
||||
test.AssertComputedAttributes(t, cird, []string{
|
||||
mkIPSetCIDRName,
|
||||
mkIPSetCIDRNoMatch,
|
||||
mkIPSetCIDRComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, cirdSchema, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, cird, map[string]schema.ValueType{
|
||||
mkIPSetCIDRName: schema.TypeString,
|
||||
mkIPSetCIDRNoMatch: schema.TypeBool,
|
||||
mkIPSetCIDRComment: schema.TypeString,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestIPSetsSchemaInstantiation tests whether the IPSetsSchema instance can be instantiated.
|
||||
@ -25,13 +25,13 @@ func TestIPSetsSchemaInstantiation(t *testing.T) {
|
||||
func TestIPSetsSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := IPSetsSchema()
|
||||
r := schema.Resource{Schema: IPSetsSchema()}
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkIPSetsIPSetNames,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkIPSetsIPSetNames: schema.TypeList,
|
||||
})
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestRuleInstantiation tests whether the RuleSchema instance can be instantiated.
|
||||
@ -25,14 +25,14 @@ func TestRuleSchemaInstantiation(t *testing.T) {
|
||||
func TestRuleSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ruleSchema := RuleSchema()
|
||||
r := schema.Resource{Schema: RuleSchema()}
|
||||
|
||||
structure.AssertRequiredArguments(t, ruleSchema, []string{
|
||||
test.AssertRequiredArguments(t, &r, []string{
|
||||
mkRuleAction,
|
||||
mkRuleType,
|
||||
})
|
||||
|
||||
structure.AssertComputedAttributes(t, ruleSchema, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkRuleComment,
|
||||
mkRuleDest,
|
||||
mkRuleDPort,
|
||||
@ -45,7 +45,7 @@ func TestRuleSchema(t *testing.T) {
|
||||
mkRuleSPort,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, ruleSchema, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkRulePos: schema.TypeInt,
|
||||
mkRuleAction: schema.TypeString,
|
||||
mkRuleType: schema.TypeString,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestSecurityGroupSchemaInstantiation tests whether the SecurityGroupSchema instance can be instantiated.
|
||||
@ -25,18 +25,18 @@ func TestSecurityGroupSchemaInstantiation(t *testing.T) {
|
||||
func TestSecurityGroupSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := SecurityGroupSchema()
|
||||
r := schema.Resource{Schema: SecurityGroupSchema()}
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, &r, []string{
|
||||
mkSecurityGroupName,
|
||||
})
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkSecurityGroupComment,
|
||||
mkRules,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkSecurityGroupName: schema.TypeString,
|
||||
mkSecurityGroupComment: schema.TypeString,
|
||||
mkRules: schema.TypeList,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestSecurityGroupsSchemaInstantiation tests whether the SecurityGroupsSchema instance can be instantiated.
|
||||
@ -25,13 +25,13 @@ func TestSecurityGroupsSchemaInstantiation(t *testing.T) {
|
||||
func TestSecurityGroupsSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := SecurityGroupsSchema()
|
||||
r := schema.Resource{Schema: SecurityGroupsSchema()}
|
||||
|
||||
structure.AssertComputedAttributes(t, s, []string{
|
||||
test.AssertComputedAttributes(t, &r, []string{
|
||||
mkSecurityGroupsSecurityGroupNames,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, &r, map[string]schema.ValueType{
|
||||
mkSecurityGroupsSecurityGroupNames: schema.TypeList,
|
||||
})
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/firewall"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestSecurityGroupInstantiation tests whether the SecurityGroup instance can be instantiated.
|
||||
@ -26,20 +26,20 @@ func TestSecurityGroupInstantiation(t *testing.T) {
|
||||
func TestSecurityGroupSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := SecurityGroup().Schema
|
||||
s := SecurityGroup()
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, s, []string{
|
||||
mkSecurityGroupName,
|
||||
})
|
||||
|
||||
structure.AssertOptionalArguments(t, s, []string{
|
||||
test.AssertOptionalArguments(t, s, []string{
|
||||
mkSecurityGroupComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
mkSecurityGroupName: schema.TypeString,
|
||||
mkSecurityGroupComment: schema.TypeString,
|
||||
})
|
||||
|
||||
structure.AssertNestedSchemaExistence(t, s, firewall.MkRule)
|
||||
test.AssertNestedSchemaExistence(t, s, firewall.MkRule)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/containers"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -571,7 +572,7 @@ func Container() *schema.Resource {
|
||||
Description: "Volume size (only used for volume mount points)",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentContainerMountPointSize,
|
||||
ValidateDiagFunc: getFileSizeValidator(),
|
||||
ValidateDiagFunc: validator.FileSize(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentContainerMountPointVolume: {
|
||||
Type: schema.TypeString,
|
||||
@ -618,7 +619,7 @@ func Container() *schema.Resource {
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return new == ""
|
||||
},
|
||||
ValidateDiagFunc: getMACAddressValidator(),
|
||||
ValidateDiagFunc: validator.MACAddress(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentContainerNetworkInterfaceName: {
|
||||
Type: schema.TypeString,
|
||||
@ -666,7 +667,7 @@ func Container() *schema.Resource {
|
||||
Description: "The ID of an OS template file",
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentContainerOperatingSystemType: {
|
||||
Type: schema.TypeString,
|
||||
@ -704,7 +705,7 @@ func Container() *schema.Resource {
|
||||
Type: schema.TypeString,
|
||||
ValidateFunc: validation.StringIsNotEmpty,
|
||||
},
|
||||
DiffSuppressFunc: suppressIfListsAreEqualIgnoringOrder,
|
||||
DiffSuppressFunc: structure.SuppressIfListsAreEqualIgnoringOrder,
|
||||
DiffSuppressOnRefresh: true,
|
||||
},
|
||||
mkResourceVirtualEnvironmentContainerTemplate: {
|
||||
@ -1123,7 +1124,7 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentContainerNodeName).(string)
|
||||
resource := Container()
|
||||
|
||||
consoleBlock, err := getSchemaBlock(
|
||||
consoleBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerConsole},
|
||||
@ -1140,7 +1141,7 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
consoleMode := consoleBlock[mkResourceVirtualEnvironmentContainerConsoleMode].(string)
|
||||
consoleTTYCount := consoleBlock[mkResourceVirtualEnvironmentContainerConsoleTTYCount].(int)
|
||||
|
||||
cpuBlock, err := getSchemaBlock(
|
||||
cpuBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerCPU},
|
||||
@ -1157,7 +1158,7 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
|
||||
description := d.Get(mkResourceVirtualEnvironmentContainerDescription).(string)
|
||||
|
||||
diskBlock, err := getSchemaBlock(
|
||||
diskBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerDisk},
|
||||
@ -1181,7 +1182,7 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
featuresBlock, err := getSchemaBlock(
|
||||
featuresBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerFeatures},
|
||||
@ -1282,7 +1283,7 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
}
|
||||
}
|
||||
|
||||
memoryBlock, err := getSchemaBlock(
|
||||
memoryBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerMemory},
|
||||
@ -2273,7 +2274,7 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
// Prepare the new console configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentContainerConsole) {
|
||||
consoleBlock, err := getSchemaBlock(
|
||||
consoleBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerConsole},
|
||||
@ -2299,7 +2300,7 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
// Prepare the new CPU configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentContainerCPU) {
|
||||
cpuBlock, err := getSchemaBlock(
|
||||
cpuBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerCPU},
|
||||
@ -2396,7 +2397,7 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
// Prepare the new memory configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentContainerMemory) {
|
||||
memoryBlock, err := getSchemaBlock(
|
||||
memoryBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerMemory},
|
||||
@ -2561,7 +2562,7 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
// Prepare the new operating system configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentContainerOperatingSystem) {
|
||||
operatingSystem, err := getSchemaBlock(
|
||||
operatingSystem, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentContainerOperatingSystem},
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
|
||||
"github.com/bpg/terraform-provider-proxmox/utils"
|
||||
)
|
||||
|
||||
@ -69,7 +70,7 @@ func File() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentFileContentType,
|
||||
ValidateDiagFunc: getContentTypeValidator(),
|
||||
ValidateDiagFunc: validator.ContentType(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentFileDatastoreID: {
|
||||
Type: schema.TypeString,
|
||||
@ -523,7 +524,7 @@ func fileGetContentType(d *schema.ResourceData) (*string, diag.Diagnostics) {
|
||||
}
|
||||
}
|
||||
|
||||
ctValidator := getContentTypeValidator()
|
||||
ctValidator := validator.ContentType()
|
||||
diags := ctValidator(contentType, cty.GetAttrPath(mkResourceVirtualEnvironmentFileContentType))
|
||||
|
||||
return &contentType, diags
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestAliasInstantiation tests whether the Alias instance can be instantiated.
|
||||
@ -25,20 +25,20 @@ func TestAliasInstantiation(t *testing.T) {
|
||||
func TestAliasSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := Alias().Schema
|
||||
s := Alias()
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, s, []string{
|
||||
mkAliasName,
|
||||
mkAliasCIDR,
|
||||
})
|
||||
|
||||
structure.AssertOptionalArguments(t, s, []string{
|
||||
test.AssertOptionalArguments(t, s, []string{
|
||||
mkSelectorVMID,
|
||||
mkSelectorNodeName,
|
||||
mkAliasComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
mkAliasName: schema.TypeString,
|
||||
mkAliasCIDR: schema.TypeString,
|
||||
mkAliasComment: schema.TypeString,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestIPSetInstantiation tests whether the IPSet
|
||||
@ -26,37 +26,37 @@ func TestIPSetInstantiation(t *testing.T) {
|
||||
func TestIPSetSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := IPSet().Schema
|
||||
s := IPSet()
|
||||
|
||||
structure.AssertRequiredArguments(t, s, []string{
|
||||
test.AssertRequiredArguments(t, s, []string{
|
||||
mkIPSetName,
|
||||
})
|
||||
|
||||
structure.AssertOptionalArguments(t, s, []string{
|
||||
test.AssertOptionalArguments(t, s, []string{
|
||||
mkSelectorVMID,
|
||||
mkSelectorNodeName,
|
||||
mkIPSetCIDR,
|
||||
mkIPSetCIDRComment,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
mkIPSetName: schema.TypeString,
|
||||
mkIPSetCIDR: schema.TypeList,
|
||||
mkIPSetCIDRComment: schema.TypeString,
|
||||
})
|
||||
|
||||
nested := structure.AssertNestedSchemaExistence(t, s, mkIPSetCIDR).Schema
|
||||
nested := test.AssertNestedSchemaExistence(t, s, mkIPSetCIDR)
|
||||
|
||||
structure.AssertRequiredArguments(t, nested, []string{
|
||||
test.AssertRequiredArguments(t, nested, []string{
|
||||
mkIPSetCIDRName,
|
||||
})
|
||||
|
||||
structure.AssertOptionalArguments(t, nested, []string{
|
||||
test.AssertOptionalArguments(t, nested, []string{
|
||||
mkIPSetCIDRComment,
|
||||
mkIPSetCIDRNoMatch,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, nested, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, nested, map[string]schema.ValueType{
|
||||
mkIPSetCIDRName: schema.TypeString,
|
||||
mkIPSetCIDRComment: schema.TypeString,
|
||||
mkIPSetCIDRNoMatch: schema.TypeBool,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestOptionsInstantiation tests whether the Options instance can be instantiated.
|
||||
@ -25,9 +25,9 @@ func TestOptionsInstantiation(t *testing.T) {
|
||||
func TestOptionsSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := Options().Schema
|
||||
s := Options()
|
||||
|
||||
structure.AssertOptionalArguments(t, s, []string{
|
||||
test.AssertOptionalArguments(t, s, []string{
|
||||
mkDHCP,
|
||||
mkEnabled,
|
||||
mkIPFilter,
|
||||
@ -40,7 +40,7 @@ func TestOptionsSchema(t *testing.T) {
|
||||
mkRadv,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, s, map[string]schema.ValueType{
|
||||
mkDHCP: schema.TypeBool,
|
||||
mkEnabled: schema.TypeBool,
|
||||
mkIPFilter: schema.TypeBool,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
|
||||
// TestRuleInstantiation tests whether the Rules instance can be instantiated.
|
||||
@ -25,20 +25,20 @@ func TestRuleInstantiation(t *testing.T) {
|
||||
func TestRuleSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rulesSchema := Rules().Schema
|
||||
rules := Rules()
|
||||
|
||||
structure.AssertRequiredArguments(t, rulesSchema, []string{
|
||||
test.AssertRequiredArguments(t, rules, []string{
|
||||
MkRule,
|
||||
})
|
||||
|
||||
structure.AssertOptionalArguments(t, rulesSchema, []string{
|
||||
test.AssertOptionalArguments(t, rules, []string{
|
||||
mkSelectorVMID,
|
||||
mkSelectorNodeName,
|
||||
})
|
||||
|
||||
ruleSchema := structure.AssertNestedSchemaExistence(t, rulesSchema, MkRule).Schema
|
||||
nested := test.AssertNestedSchemaExistence(t, rules, MkRule)
|
||||
|
||||
structure.AssertOptionalArguments(t, ruleSchema, []string{
|
||||
test.AssertOptionalArguments(t, nested, []string{
|
||||
mkSecurityGroup,
|
||||
mkRuleAction,
|
||||
mkRuleType,
|
||||
@ -54,7 +54,7 @@ func TestRuleSchema(t *testing.T) {
|
||||
mkRuleSPort,
|
||||
})
|
||||
|
||||
structure.AssertValueTypes(t, ruleSchema, map[string]schema.ValueType{
|
||||
test.AssertValueTypes(t, nested, map[string]schema.ValueType{
|
||||
mkRulePos: schema.TypeInt,
|
||||
mkRuleAction: schema.TypeString,
|
||||
mkRuleType: schema.TypeString,
|
||||
|
@ -1,582 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/internal/types"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
|
||||
)
|
||||
|
||||
func getBIOSValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"ovmf",
|
||||
"seabios",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func getContentTypeValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"backup",
|
||||
"iso",
|
||||
"snippets",
|
||||
"vztmpl",
|
||||
}, false))
|
||||
}
|
||||
|
||||
//nolint:unused
|
||||
func getCPUFlagsValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
|
||||
list, ok := i.([]interface{})
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be []interface{}", k))
|
||||
return
|
||||
}
|
||||
|
||||
validator := validation.StringInSlice([]string{
|
||||
"+aes",
|
||||
"-aes",
|
||||
"+amd-no-ssb",
|
||||
"-amd-no-ssb",
|
||||
"+amd-ssbd",
|
||||
"-amd-ssbd",
|
||||
"+hv-evmcs",
|
||||
"-hv-evmcs",
|
||||
"+hv-tlbflush",
|
||||
"-hv-tlbflush",
|
||||
"+ibpb",
|
||||
"-ibpb",
|
||||
"+md-clear",
|
||||
"-md-clear",
|
||||
"+pcid",
|
||||
"-pcid",
|
||||
"+pdpe1gb",
|
||||
"-pdpe1gb",
|
||||
"+spec-ctrl",
|
||||
"-spec-ctrl",
|
||||
"+ssbd",
|
||||
"-ssbd",
|
||||
"+virt-ssbd",
|
||||
"-virt-ssbd",
|
||||
}, false)
|
||||
|
||||
for li, lv := range list {
|
||||
v, ok := lv.(string)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s[%d] to be string", k, li))
|
||||
return
|
||||
}
|
||||
|
||||
warns, errs := validator(v, k)
|
||||
|
||||
ws = append(ws, warns...)
|
||||
es = append(es, errs...)
|
||||
|
||||
if len(es) > 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func getCPUTypeValidator() schema.SchemaValidateDiagFunc {
|
||||
standardTypes := []string{
|
||||
"486",
|
||||
"Broadwell",
|
||||
"Broadwell-IBRS",
|
||||
"Broadwell-noTSX",
|
||||
"Broadwell-noTSX-IBRS",
|
||||
"Cascadelake-Server",
|
||||
"Cascadelake-Server-noTSX",
|
||||
"Cascadelake-Server-v2",
|
||||
"Cascadelake-Server-v4",
|
||||
"Cascadelake-Server-v5",
|
||||
"Conroe",
|
||||
"Cooperlake",
|
||||
"Cooperlake-v2",
|
||||
"EPYC",
|
||||
"EPYC-IBPB",
|
||||
"EPYC-Milan",
|
||||
"EPYC-Rome",
|
||||
"EPYC-Rome-v2",
|
||||
"EPYC-v3",
|
||||
"Haswell",
|
||||
"Haswell-IBRS",
|
||||
"Haswell-noTSX",
|
||||
"Haswell-noTSX-IBRS",
|
||||
"Icelake-Client",
|
||||
"Icelake-Client-noTSX",
|
||||
"Icelake-Server",
|
||||
"Icelake-Server-noTSX",
|
||||
"Icelake-Server-v3",
|
||||
"Icelake-Server-v4",
|
||||
"Icelake-Server-v5",
|
||||
"Icelake-Server-v6",
|
||||
"IvyBridge",
|
||||
"IvyBridge-IBRS",
|
||||
"KnightsMill",
|
||||
"Nehalem",
|
||||
"Nehalem-IBRS",
|
||||
"Opteron_G1",
|
||||
"Opteron_G2",
|
||||
"Opteron_G3",
|
||||
"Opteron_G4",
|
||||
"Opteron_G5",
|
||||
"Penryn",
|
||||
"SandyBridge",
|
||||
"SandyBridge-IBRS",
|
||||
"SapphireRapids",
|
||||
"Skylake-Client",
|
||||
"Skylake-Client-IBRS",
|
||||
"Skylake-Client-noTSX-IBRS",
|
||||
"Skylake-Client-v4",
|
||||
"Skylake-Server",
|
||||
"Skylake-Server-IBRS",
|
||||
"Skylake-Server-noTSX-IBRS",
|
||||
"Skylake-Server-v4",
|
||||
"Skylake-Server-v5",
|
||||
"Westmere",
|
||||
"Westmere-IBRS",
|
||||
"athlon",
|
||||
"core2duo",
|
||||
"coreduo",
|
||||
"host",
|
||||
"kvm32",
|
||||
"kvm64",
|
||||
"max",
|
||||
"pentium",
|
||||
"pentium2",
|
||||
"pentium3",
|
||||
"phenom",
|
||||
"qemu32",
|
||||
"qemu64",
|
||||
"x86-64-v2",
|
||||
"x86-64-v2-AES",
|
||||
"x86-64-v3",
|
||||
"x86-64-v4",
|
||||
}
|
||||
|
||||
return validation.ToDiagFunc(validation.Any(
|
||||
validation.StringInSlice(standardTypes, false),
|
||||
validation.StringMatch(regexp.MustCompile(`^custom-.+$`), "must be a valid custom CPU type"),
|
||||
))
|
||||
}
|
||||
|
||||
func getFileFormatValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"qcow2",
|
||||
"raw",
|
||||
"vmdk",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func getFileIDValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
|
||||
v, ok := i.(string)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
r := regexp.MustCompile(`^(?i)[a-z\d\-_]+:([a-z\d\-_]+/)?.+$`)
|
||||
ok := r.MatchString(v)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected %s to be a valid file identifier (datastore-name:iso/some-file.img), got %s", k, v))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func getFileSizeValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
|
||||
v, ok := i.(string)
|
||||
var es []error
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return nil, es
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
_, err := types.ParseDiskSize(v)
|
||||
if err != nil {
|
||||
es = append(es, fmt.Errorf("expected %s to be a valid file size (100, 1M, 1G), got %s", k, v))
|
||||
return nil, es
|
||||
}
|
||||
}
|
||||
|
||||
return []string{}, es
|
||||
})
|
||||
}
|
||||
|
||||
func getKeyboardLayoutValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"da",
|
||||
"de",
|
||||
"de-ch",
|
||||
"en-gb",
|
||||
"en-us",
|
||||
"es",
|
||||
"fi",
|
||||
"fr",
|
||||
"fr-be",
|
||||
"fr-ca",
|
||||
"fr-ch",
|
||||
"hu",
|
||||
"is",
|
||||
"it",
|
||||
"ja",
|
||||
"lt",
|
||||
"mk",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt",
|
||||
"pt-br",
|
||||
"sl",
|
||||
"sv",
|
||||
"tr",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func diskDigitPrefix(s string) string {
|
||||
for i, r := range s {
|
||||
if unicode.IsDigit(r) {
|
||||
return s[:i]
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func getMACAddressValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
|
||||
v, ok := i.(string)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
r := regexp.MustCompile(`^[A-Z\d]{2}(:[A-Z\d]{2}){5}$`)
|
||||
ok := r.MatchString(v)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected %s to be a valid MAC address (A0:B1:C2:D3:E4:F5), got %s", k, v))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func getNetworkDeviceModelValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{"e1000", "rtl8139", "virtio", "vmxnet3"}, false))
|
||||
}
|
||||
|
||||
func getQEMUAgentTypeValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{"isa", "virtio"}, false))
|
||||
}
|
||||
|
||||
func getSchemaBlock(r *schema.Resource, d *schema.ResourceData, k []string, i int, allowDefault bool) (map[string]interface{}, error) {
|
||||
var resourceBlock map[string]interface{}
|
||||
var resourceData interface{}
|
||||
var resourceSchema *schema.Schema
|
||||
|
||||
for ki, kv := range k {
|
||||
if ki == 0 {
|
||||
resourceData = d.Get(kv)
|
||||
resourceSchema = r.Schema[kv]
|
||||
} else {
|
||||
mapValues := resourceData.([]interface{})
|
||||
|
||||
if len(mapValues) <= i {
|
||||
return resourceBlock, fmt.Errorf("index out of bounds %d", i)
|
||||
}
|
||||
|
||||
mapValue := mapValues[i].(map[string]interface{})
|
||||
|
||||
resourceData = mapValue[kv]
|
||||
resourceSchema = resourceSchema.Elem.(*schema.Resource).Schema[kv]
|
||||
}
|
||||
}
|
||||
|
||||
list := resourceData.([]interface{})
|
||||
|
||||
if len(list) == 0 {
|
||||
if allowDefault {
|
||||
listDefault, err := resourceSchema.DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = listDefault.([]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if len(list) > i {
|
||||
resourceBlock = list[i].(map[string]interface{})
|
||||
}
|
||||
|
||||
return resourceBlock, nil
|
||||
}
|
||||
|
||||
func getTimeoutValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
|
||||
v, ok := i.(string)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return
|
||||
}
|
||||
|
||||
_, err := time.ParseDuration(v)
|
||||
|
||||
if err != nil {
|
||||
es = append(es, fmt.Errorf("expected value of %s to be a duration - got: %s", k, v))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func getVGAMemoryValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.IntBetween(4, 512))
|
||||
}
|
||||
|
||||
func getVGATypeValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"cirrus",
|
||||
"qxl",
|
||||
"qxl2",
|
||||
"qxl3",
|
||||
"qxl4",
|
||||
"serial0",
|
||||
"serial1",
|
||||
"serial2",
|
||||
"serial3",
|
||||
"std",
|
||||
"virtio",
|
||||
"vmware",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func getSCSIHardwareValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"lsi",
|
||||
"lsi53c810",
|
||||
"virtio-scsi-pci",
|
||||
"virtio-scsi-single",
|
||||
"megasas",
|
||||
"pvscsi",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func getIDEInterfaceValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"ide0",
|
||||
"ide1",
|
||||
"ide2",
|
||||
"ide3",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// suppressIfListsAreEqualIgnoringOrder is a customdiff.SuppressionFunc that suppresses
|
||||
// changes to a list if the old and new lists are equal, ignoring the order of the
|
||||
// elements.
|
||||
// It will be called for each list item, so it is not super efficient. It is
|
||||
// recommended to use it only for small lists.
|
||||
// Ref: https://github.com/hashicorp/terraform-plugin-sdk/issues/477
|
||||
func suppressIfListsAreEqualIgnoringOrder(key, _, _ string, d *schema.ResourceData) bool {
|
||||
// the key is a path to the list item, not the list itself, e.g. "tags.0"
|
||||
lastDotIndex := strings.LastIndex(key, ".")
|
||||
if lastDotIndex != -1 {
|
||||
key = key[:lastDotIndex]
|
||||
}
|
||||
|
||||
oldData, newData := d.GetChange(key)
|
||||
if oldData == nil || newData == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
oldArray := oldData.([]interface{})
|
||||
newArray := newData.([]interface{})
|
||||
|
||||
if len(oldArray) != len(newArray) {
|
||||
return false
|
||||
}
|
||||
|
||||
oldEvents := make([]string, len(oldArray))
|
||||
newEvents := make([]string, len(newArray))
|
||||
|
||||
for i, oldEvt := range oldArray {
|
||||
oldEvents[i] = fmt.Sprint(oldEvt)
|
||||
}
|
||||
|
||||
for j, newEvt := range newArray {
|
||||
newEvents[j] = fmt.Sprint(newEvt)
|
||||
}
|
||||
|
||||
sort.Strings(oldEvents)
|
||||
sort.Strings(newEvents)
|
||||
|
||||
return reflect.DeepEqual(oldEvents, newEvents)
|
||||
}
|
||||
|
||||
func getDiskInfo(resp *vms.GetResponseData, d *schema.ResourceData) map[string]*vms.CustomStorageDevice {
|
||||
currentDisk := d.Get(mkResourceVirtualEnvironmentVMDisk)
|
||||
|
||||
currentDiskList := currentDisk.([]interface{})
|
||||
currentDiskMap := map[string]map[string]interface{}{}
|
||||
|
||||
for _, v := range currentDiskList {
|
||||
diskMap := v.(map[string]interface{})
|
||||
diskInterface := diskMap[mkResourceVirtualEnvironmentVMDiskInterface].(string)
|
||||
|
||||
currentDiskMap[diskInterface] = diskMap
|
||||
}
|
||||
|
||||
storageDevices := map[string]*vms.CustomStorageDevice{}
|
||||
|
||||
storageDevices["ide0"] = resp.IDEDevice0
|
||||
storageDevices["ide1"] = resp.IDEDevice1
|
||||
storageDevices["ide2"] = resp.IDEDevice2
|
||||
storageDevices["ide3"] = resp.IDEDevice3
|
||||
|
||||
storageDevices["sata0"] = resp.SATADevice0
|
||||
storageDevices["sata1"] = resp.SATADevice1
|
||||
storageDevices["sata2"] = resp.SATADevice2
|
||||
storageDevices["sata3"] = resp.SATADevice3
|
||||
storageDevices["sata4"] = resp.SATADevice4
|
||||
storageDevices["sata5"] = resp.SATADevice5
|
||||
|
||||
storageDevices["scsi0"] = resp.SCSIDevice0
|
||||
storageDevices["scsi1"] = resp.SCSIDevice1
|
||||
storageDevices["scsi2"] = resp.SCSIDevice2
|
||||
storageDevices["scsi3"] = resp.SCSIDevice3
|
||||
storageDevices["scsi4"] = resp.SCSIDevice4
|
||||
storageDevices["scsi5"] = resp.SCSIDevice5
|
||||
storageDevices["scsi6"] = resp.SCSIDevice6
|
||||
storageDevices["scsi7"] = resp.SCSIDevice7
|
||||
storageDevices["scsi8"] = resp.SCSIDevice8
|
||||
storageDevices["scsi9"] = resp.SCSIDevice9
|
||||
storageDevices["scsi10"] = resp.SCSIDevice10
|
||||
storageDevices["scsi11"] = resp.SCSIDevice11
|
||||
storageDevices["scsi12"] = resp.SCSIDevice12
|
||||
storageDevices["scsi13"] = resp.SCSIDevice13
|
||||
|
||||
storageDevices["virtio0"] = resp.VirtualIODevice0
|
||||
storageDevices["virtio1"] = resp.VirtualIODevice1
|
||||
storageDevices["virtio2"] = resp.VirtualIODevice2
|
||||
storageDevices["virtio3"] = resp.VirtualIODevice3
|
||||
storageDevices["virtio4"] = resp.VirtualIODevice4
|
||||
storageDevices["virtio5"] = resp.VirtualIODevice5
|
||||
storageDevices["virtio6"] = resp.VirtualIODevice6
|
||||
storageDevices["virtio7"] = resp.VirtualIODevice7
|
||||
storageDevices["virtio8"] = resp.VirtualIODevice8
|
||||
storageDevices["virtio9"] = resp.VirtualIODevice9
|
||||
storageDevices["virtio10"] = resp.VirtualIODevice10
|
||||
storageDevices["virtio11"] = resp.VirtualIODevice11
|
||||
storageDevices["virtio12"] = resp.VirtualIODevice12
|
||||
storageDevices["virtio13"] = resp.VirtualIODevice13
|
||||
storageDevices["virtio14"] = resp.VirtualIODevice14
|
||||
storageDevices["virtio15"] = resp.VirtualIODevice15
|
||||
|
||||
for k, v := range storageDevices {
|
||||
if v != nil {
|
||||
if currentDiskMap[k] != nil {
|
||||
if currentDiskMap[k][mkResourceVirtualEnvironmentVMDiskFileID] != nil {
|
||||
fileID := currentDiskMap[k][mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
v.FileID = &fileID
|
||||
}
|
||||
}
|
||||
// defensive copy of the loop variable
|
||||
iface := k
|
||||
v.Interface = &iface
|
||||
}
|
||||
}
|
||||
|
||||
return storageDevices
|
||||
}
|
||||
|
||||
// getDiskDatastores returns a list of the used datastores in a VM
|
||||
func getDiskDatastores(vm *vms.GetResponseData, d *schema.ResourceData) []string {
|
||||
storageDevices := getDiskInfo(vm, d)
|
||||
datastoresSet := map[string]int{}
|
||||
|
||||
for _, diskInfo := range storageDevices {
|
||||
// Ignore empty storage devices and storage devices (like ide) which may not have any media mounted
|
||||
if diskInfo == nil || diskInfo.FileVolume == "none" {
|
||||
continue
|
||||
}
|
||||
fileIDParts := strings.Split(diskInfo.FileVolume, ":")
|
||||
datastoresSet[fileIDParts[0]] = 1
|
||||
}
|
||||
|
||||
if vm.EFIDisk != nil {
|
||||
fileIDParts := strings.Split(vm.EFIDisk.FileVolume, ":")
|
||||
datastoresSet[fileIDParts[0]] = 1
|
||||
}
|
||||
|
||||
datastores := []string{}
|
||||
for datastore := range datastoresSet {
|
||||
datastores = append(datastores, datastore)
|
||||
}
|
||||
|
||||
return datastores
|
||||
}
|
||||
|
||||
func getPCIInfo(resp *vms.GetResponseData, _ *schema.ResourceData) map[string]*vms.CustomPCIDevice {
|
||||
pciDevices := map[string]*vms.CustomPCIDevice{}
|
||||
|
||||
pciDevices["hostpci0"] = resp.PCIDevice0
|
||||
pciDevices["hostpci1"] = resp.PCIDevice1
|
||||
pciDevices["hostpci2"] = resp.PCIDevice2
|
||||
pciDevices["hostpci3"] = resp.PCIDevice3
|
||||
|
||||
return pciDevices
|
||||
}
|
||||
|
||||
func getCloudInitTypeValidator() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"configdrive2",
|
||||
"nocloud",
|
||||
}, false))
|
||||
}
|
||||
|
||||
func parseImportIDWithNodeName(id string) (string, string, error) {
|
||||
nodeName, id, found := strings.Cut(id, "/")
|
||||
|
||||
if !found {
|
||||
return "", "", fmt.Errorf("unexpected format of ID (%s), expected node/id", id)
|
||||
}
|
||||
|
||||
return nodeName, id, nil
|
||||
}
|
78
proxmoxtf/resource/validator/file.go
Normal file
78
proxmoxtf/resource/validator/file.go
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/internal/types"
|
||||
)
|
||||
|
||||
// FileFormat returns a schema validation function for a file format.
|
||||
func FileFormat() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"qcow2",
|
||||
"raw",
|
||||
"vmdk",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// FileID returns a schema validation function for a file identifier.
|
||||
func FileID() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
|
||||
v, ok := i.(string)
|
||||
|
||||
var ws []string
|
||||
var es []error
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
r := regexp.MustCompile(`^(?i)[a-z\d\-_]+:([a-z\d\-_]+/)?.+$`)
|
||||
ok := r.MatchString(v)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf(
|
||||
"expected %s to be a valid file identifier (datastore-name:iso/some-file.img), got %s", k, v,
|
||||
))
|
||||
return ws, es
|
||||
}
|
||||
}
|
||||
|
||||
return ws, es
|
||||
})
|
||||
}
|
||||
|
||||
// FileSize is a schema validation function for file size.
|
||||
func FileSize() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
|
||||
v, ok := i.(string)
|
||||
var es []error
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return nil, es
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
_, err := types.ParseDiskSize(v)
|
||||
if err != nil {
|
||||
es = append(es, fmt.Errorf("expected %s to be a valid file size (100, 1M, 1G), got %s", k, v))
|
||||
return nil, es
|
||||
}
|
||||
}
|
||||
|
||||
return []string{}, es
|
||||
})
|
||||
}
|
@ -8,69 +8,35 @@ package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||
)
|
||||
|
||||
// VLANIDsValidator returns a schema validation function for VLAN IDs.
|
||||
func VLANIDsValidator() schema.SchemaValidateDiagFunc {
|
||||
// MACAddress is a schema validation function for MAC address.
|
||||
func MACAddress() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
|
||||
min := 1
|
||||
max := 4094
|
||||
v, ok := i.(string)
|
||||
|
||||
var ws []string
|
||||
var es []error
|
||||
|
||||
list, ok := i.([]interface{})
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
if v != "" {
|
||||
r := regexp.MustCompile(`^[A-Z\d]{2}(:[A-Z\d]{2}){5}$`)
|
||||
ok := r.MatchString(v)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be []interface{}", k))
|
||||
es = append(es, fmt.Errorf("expected %s to be a valid MAC address (A0:B1:C2:D3:E4:F5), got %s", k, v))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
for li, lv := range list {
|
||||
v, ok := lv.(int)
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s[%d] to be int", k, li))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
if v != -1 {
|
||||
if v < min || v > max {
|
||||
es = append(es, fmt.Errorf("expected %s[%d] to be in the range (%d - %d), got %d", k, li, min, max, v))
|
||||
return ws, es
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ws, es
|
||||
})
|
||||
}
|
||||
|
||||
// NodeNetworkInterfaceBondingModes returns a schema validation function for a node network interface bonding mode.
|
||||
func NodeNetworkInterfaceBondingModes() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"balance-rr",
|
||||
"active-backup",
|
||||
"balance-xor",
|
||||
"broadcast",
|
||||
"802.3ad",
|
||||
"balance-tlb",
|
||||
"balance-alb",
|
||||
"balance-slb",
|
||||
"lacp-balance-slb",
|
||||
"lacp-balance-tcp",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// NodeNetworkInterfaceBondingTransmitHashPolicies returns a schema validation function for a node network interface
|
||||
// bonding transmit hash policy.
|
||||
func NodeNetworkInterfaceBondingTransmitHashPolicies() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"layer2",
|
||||
"layer2+3",
|
||||
"layer3+4",
|
||||
}, false))
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
||||
@ -39,3 +41,222 @@ func VMID() schema.SchemaValidateDiagFunc {
|
||||
return ws, es
|
||||
})
|
||||
}
|
||||
|
||||
// BIOS returns a schema validation function for a BIOS type.
|
||||
func BIOS() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"ovmf",
|
||||
"seabios",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// ContentType returns a schema validation function for a content type on a storage device.
|
||||
func ContentType() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"backup",
|
||||
"iso",
|
||||
"snippets",
|
||||
"vztmpl",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// CPUType returns a schema validation function for a CPU type.
|
||||
func CPUType() schema.SchemaValidateDiagFunc {
|
||||
standardTypes := []string{
|
||||
"486",
|
||||
"Broadwell",
|
||||
"Broadwell-IBRS",
|
||||
"Broadwell-noTSX",
|
||||
"Broadwell-noTSX-IBRS",
|
||||
"Cascadelake-Server",
|
||||
"Cascadelake-Server-noTSX",
|
||||
"Cascadelake-Server-v2",
|
||||
"Cascadelake-Server-v4",
|
||||
"Cascadelake-Server-v5",
|
||||
"Conroe",
|
||||
"Cooperlake",
|
||||
"Cooperlake-v2",
|
||||
"EPYC",
|
||||
"EPYC-IBPB",
|
||||
"EPYC-Milan",
|
||||
"EPYC-Rome",
|
||||
"EPYC-Rome-v2",
|
||||
"EPYC-v3",
|
||||
"Haswell",
|
||||
"Haswell-IBRS",
|
||||
"Haswell-noTSX",
|
||||
"Haswell-noTSX-IBRS",
|
||||
"Icelake-Client",
|
||||
"Icelake-Client-noTSX",
|
||||
"Icelake-Server",
|
||||
"Icelake-Server-noTSX",
|
||||
"Icelake-Server-v3",
|
||||
"Icelake-Server-v4",
|
||||
"Icelake-Server-v5",
|
||||
"Icelake-Server-v6",
|
||||
"IvyBridge",
|
||||
"IvyBridge-IBRS",
|
||||
"KnightsMill",
|
||||
"Nehalem",
|
||||
"Nehalem-IBRS",
|
||||
"Opteron_G1",
|
||||
"Opteron_G2",
|
||||
"Opteron_G3",
|
||||
"Opteron_G4",
|
||||
"Opteron_G5",
|
||||
"Penryn",
|
||||
"SandyBridge",
|
||||
"SandyBridge-IBRS",
|
||||
"SapphireRapids",
|
||||
"Skylake-Client",
|
||||
"Skylake-Client-IBRS",
|
||||
"Skylake-Client-noTSX-IBRS",
|
||||
"Skylake-Client-v4",
|
||||
"Skylake-Server",
|
||||
"Skylake-Server-IBRS",
|
||||
"Skylake-Server-noTSX-IBRS",
|
||||
"Skylake-Server-v4",
|
||||
"Skylake-Server-v5",
|
||||
"Westmere",
|
||||
"Westmere-IBRS",
|
||||
"athlon",
|
||||
"core2duo",
|
||||
"coreduo",
|
||||
"host",
|
||||
"kvm32",
|
||||
"kvm64",
|
||||
"max",
|
||||
"pentium",
|
||||
"pentium2",
|
||||
"pentium3",
|
||||
"phenom",
|
||||
"qemu32",
|
||||
"qemu64",
|
||||
"x86-64-v2",
|
||||
"x86-64-v2-AES",
|
||||
"x86-64-v3",
|
||||
"x86-64-v4",
|
||||
}
|
||||
|
||||
return validation.ToDiagFunc(validation.Any(
|
||||
validation.StringInSlice(standardTypes, false),
|
||||
validation.StringMatch(regexp.MustCompile(`^custom-.+$`), "must be a valid custom CPU type"),
|
||||
))
|
||||
}
|
||||
|
||||
// NetworkDeviceModel is a schema validation function for network device models.
|
||||
func NetworkDeviceModel() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{"e1000", "rtl8139", "virtio", "vmxnet3"}, false))
|
||||
}
|
||||
|
||||
// QEMUAgentType is a schema validation function for QEMU agent types.
|
||||
func QEMUAgentType() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{"isa", "virtio"}, false))
|
||||
}
|
||||
|
||||
// KeyboardLayout is a schema validation function for keyboard layouts.
|
||||
func KeyboardLayout() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"da",
|
||||
"de",
|
||||
"de-ch",
|
||||
"en-gb",
|
||||
"en-us",
|
||||
"es",
|
||||
"fi",
|
||||
"fr",
|
||||
"fr-be",
|
||||
"fr-ca",
|
||||
"fr-ch",
|
||||
"hu",
|
||||
"is",
|
||||
"it",
|
||||
"ja",
|
||||
"lt",
|
||||
"mk",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt",
|
||||
"pt-br",
|
||||
"sl",
|
||||
"sv",
|
||||
"tr",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// Timeout is a schema validation function for timeouts.
|
||||
func Timeout() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
|
||||
v, ok := i.(string)
|
||||
|
||||
var ws []string
|
||||
var es []error
|
||||
|
||||
if !ok {
|
||||
es = append(es, fmt.Errorf("expected type of %s to be string", k))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
_, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
es = append(es, fmt.Errorf("expected value of %s to be a duration - got: %s", k, v))
|
||||
return ws, es
|
||||
}
|
||||
|
||||
return ws, es
|
||||
})
|
||||
}
|
||||
|
||||
// VGAMemory is a schema validation function for VGA memory sizes.
|
||||
func VGAMemory() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.IntBetween(4, 512))
|
||||
}
|
||||
|
||||
// VGAType is a schema validation function for VGA device types.
|
||||
func VGAType() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"cirrus",
|
||||
"qxl",
|
||||
"qxl2",
|
||||
"qxl3",
|
||||
"qxl4",
|
||||
"serial0",
|
||||
"serial1",
|
||||
"serial2",
|
||||
"serial3",
|
||||
"std",
|
||||
"virtio",
|
||||
"vmware",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// SCSIHardware is a schema validation function for SCSI hardware.
|
||||
func SCSIHardware() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"lsi",
|
||||
"lsi53c810",
|
||||
"virtio-scsi-pci",
|
||||
"virtio-scsi-single",
|
||||
"megasas",
|
||||
"pvscsi",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// IDEInterface is a schema validation function for IDE interfaces.
|
||||
func IDEInterface() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"ide0",
|
||||
"ide1",
|
||||
"ide2",
|
||||
"ide3",
|
||||
}, false))
|
||||
}
|
||||
|
||||
// CloudInitType is a schema validation function for cloud-init types.
|
||||
func CloudInitType() schema.SchemaValidateDiagFunc {
|
||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||
"configdrive2",
|
||||
"nocloud",
|
||||
}, false))
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package resource
|
||||
package validator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -33,7 +33,7 @@ func Test_getCPUTypeValidator(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
f := getCPUTypeValidator()
|
||||
f := CPUType()
|
||||
res := f(tt.value, nil)
|
||||
|
||||
if tt.valid {
|
||||
@ -44,38 +44,3 @@ func Test_getCPUTypeValidator(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseImportIDWIthNodeName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
valid bool
|
||||
expectedNodeName string
|
||||
expectedID string
|
||||
}{
|
||||
{"empty", "", false, "", ""},
|
||||
{"missing slash", "invalid", false, "", ""},
|
||||
{"valid", "host/id", true, "host", "id"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
nodeName, id, err := parseImportIDWithNodeName(tt.value)
|
||||
|
||||
if !tt.valid {
|
||||
require.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
require.Nil(err)
|
||||
require.Equal(tt.expectedNodeName, nodeName)
|
||||
require.Equal(tt.expectedID, id)
|
||||
})
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
|
||||
@ -25,6 +26,7 @@ import (
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -305,7 +307,7 @@ func VM() *schema.Resource {
|
||||
Description: "The maximum amount of time to wait for data from the QEMU agent to become available",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMAgentTimeout,
|
||||
ValidateDiagFunc: getTimeoutValidator(),
|
||||
ValidateDiagFunc: validator.Timeout(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMAgentTrim: {
|
||||
Type: schema.TypeBool,
|
||||
@ -318,7 +320,7 @@ func VM() *schema.Resource {
|
||||
Description: "The QEMU agent interface type",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMAgentType,
|
||||
ValidateDiagFunc: getQEMUAgentTypeValidator(),
|
||||
ValidateDiagFunc: validator.QEMUAgentType(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -370,7 +372,7 @@ func VM() *schema.Resource {
|
||||
Description: "The BIOS implementation",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMBIOS,
|
||||
ValidateDiagFunc: getBIOSValidator(),
|
||||
ValidateDiagFunc: validator.BIOS(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMCDROM: {
|
||||
Type: schema.TypeList,
|
||||
@ -398,14 +400,14 @@ func VM() *schema.Resource {
|
||||
Description: "The file id",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMCDROMFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMCDROMInterface: {
|
||||
Type: schema.TypeString,
|
||||
Description: "The CDROM interface",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMCDROMInterface,
|
||||
ValidateDiagFunc: getIDEInterfaceValidator(),
|
||||
ValidateDiagFunc: validator.IDEInterface(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -529,7 +531,7 @@ func VM() *schema.Resource {
|
||||
Description: "The emulated CPU type",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMCPUType,
|
||||
ValidateDiagFunc: getCPUTypeValidator(),
|
||||
ValidateDiagFunc: validator.CPUType(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMCPUUnits: {
|
||||
Type: schema.TypeInt,
|
||||
@ -588,7 +590,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
ValidateDiagFunc: getFileFormatValidator(),
|
||||
ValidateDiagFunc: validator.FileFormat(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMDiskFileID: {
|
||||
Type: schema.TypeString,
|
||||
@ -596,7 +598,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMDiskFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMDiskSize: {
|
||||
Type: schema.TypeInt,
|
||||
@ -695,7 +697,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
ValidateDiagFunc: getFileFormatValidator(),
|
||||
ValidateDiagFunc: validator.FileFormat(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMEFIDiskType: {
|
||||
Type: schema.TypeString,
|
||||
@ -875,7 +877,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMInitializationUserDataFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMInitializationVendorDataFileID: {
|
||||
Type: schema.TypeString,
|
||||
@ -883,7 +885,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMInitializationVendorDataFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMInitializationNetworkDataFileID: {
|
||||
Type: schema.TypeString,
|
||||
@ -891,7 +893,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMInitializationNetworkDataFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMInitializationMetaDataFileID: {
|
||||
Type: schema.TypeString,
|
||||
@ -899,7 +901,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMInitializationMetaDataFileID,
|
||||
ValidateDiagFunc: getFileIDValidator(),
|
||||
ValidateDiagFunc: validator.FileID(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMInitializationType: {
|
||||
Type: schema.TypeString,
|
||||
@ -907,7 +909,7 @@ func VM() *schema.Resource {
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: dvResourceVirtualEnvironmentVMInitializationType,
|
||||
ValidateDiagFunc: getCloudInitTypeValidator(),
|
||||
ValidateDiagFunc: validator.CloudInitType(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -985,7 +987,7 @@ func VM() *schema.Resource {
|
||||
Description: "The keyboard layout",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMKeyboardLayout,
|
||||
ValidateDiagFunc: getKeyboardLayoutValidator(),
|
||||
ValidateDiagFunc: validator.KeyboardLayout(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMMachine: {
|
||||
Type: schema.TypeString,
|
||||
@ -1084,14 +1086,14 @@ func VM() *schema.Resource {
|
||||
Description: "The MAC address",
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ValidateDiagFunc: getMACAddressValidator(),
|
||||
ValidateDiagFunc: validator.MACAddress(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMNetworkDeviceModel: {
|
||||
Type: schema.TypeString,
|
||||
Description: "The model",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMNetworkDeviceModel,
|
||||
ValidateDiagFunc: getNetworkDeviceModelValidator(),
|
||||
ValidateDiagFunc: validator.NetworkDeviceModel(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMNetworkDeviceRateLimit: {
|
||||
Type: schema.TypeFloat,
|
||||
@ -1208,7 +1210,7 @@ func VM() *schema.Resource {
|
||||
Type: schema.TypeString,
|
||||
ValidateFunc: validation.StringIsNotEmpty,
|
||||
},
|
||||
DiffSuppressFunc: suppressIfListsAreEqualIgnoringOrder,
|
||||
DiffSuppressFunc: structure.SuppressIfListsAreEqualIgnoringOrder,
|
||||
DiffSuppressOnRefresh: true,
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMTemplate: {
|
||||
@ -1280,14 +1282,14 @@ func VM() *schema.Resource {
|
||||
Description: "The VGA memory in megabytes (4-512 MB)",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMVGAMemory,
|
||||
ValidateDiagFunc: getVGAMemoryValidator(),
|
||||
ValidateDiagFunc: validator.VGAMemory(),
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMVGAType: {
|
||||
Type: schema.TypeString,
|
||||
Description: "The VGA type",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMVGAType,
|
||||
ValidateDiagFunc: getVGATypeValidator(),
|
||||
ValidateDiagFunc: validator.VGAType(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1308,7 +1310,7 @@ func VM() *schema.Resource {
|
||||
Description: "The SCSI hardware type",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentVMSCSIHardware,
|
||||
ValidateDiagFunc: getSCSIHardwareValidator(),
|
||||
ValidateDiagFunc: validator.SCSIHardware(),
|
||||
},
|
||||
},
|
||||
CreateContext: vmCreate,
|
||||
@ -1975,7 +1977,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
acpi := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
|
||||
|
||||
agentBlock, err := getSchemaBlock(
|
||||
agentBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMAgent},
|
||||
@ -1998,7 +2000,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
bios := d.Get(mkResourceVirtualEnvironmentVMBIOS).(string)
|
||||
|
||||
cdromBlock, err := getSchemaBlock(
|
||||
cdromBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMCDROM},
|
||||
@ -2020,7 +2022,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
cdromFileID = "cdrom"
|
||||
}
|
||||
|
||||
cpuBlock, err := getSchemaBlock(
|
||||
cpuBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMCPU},
|
||||
@ -2088,7 +2090,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
pciDeviceObjects := vmGetHostPCIDeviceObjects(d)
|
||||
|
||||
keyboardLayout := d.Get(mkResourceVirtualEnvironmentVMKeyboardLayout).(string)
|
||||
memoryBlock, err := getSchemaBlock(
|
||||
memoryBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMMemory},
|
||||
@ -2111,7 +2113,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
|
||||
|
||||
operatingSystem, err := getSchemaBlock(
|
||||
operatingSystem, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMOperatingSystem},
|
||||
@ -2721,7 +2723,7 @@ func vmGetDiskDeviceObjects(
|
||||
ssd := types.CustomBool(block[mkResourceVirtualEnvironmentVMDiskSSD].(bool))
|
||||
discard := block[mkResourceVirtualEnvironmentVMDiskDiscard].(string)
|
||||
|
||||
speedBlock, err := getSchemaBlock(
|
||||
speedBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMDisk, mkResourceVirtualEnvironmentVMDiskSpeed},
|
||||
@ -3016,7 +3018,7 @@ func vmGetSerialDeviceValidator() schema.SchemaValidateDiagFunc {
|
||||
func vmGetVGADeviceObject(d *schema.ResourceData) (*vms.CustomVGADevice, error) {
|
||||
resource := VM()
|
||||
|
||||
vgaBlock, err := getSchemaBlock(
|
||||
vgaBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMVGA},
|
||||
@ -4126,7 +4128,7 @@ func vmReadNetworkValues(
|
||||
if started {
|
||||
if vmConfig.Agent != nil && vmConfig.Agent.Enabled != nil && *vmConfig.Agent.Enabled {
|
||||
resource := VM()
|
||||
agentBlock, err := getSchemaBlock(
|
||||
agentBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMAgent},
|
||||
@ -4453,7 +4455,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
// Prepare the new agent configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentVMAgent) {
|
||||
agentBlock, err := getSchemaBlock(
|
||||
agentBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMAgent},
|
||||
@ -4513,7 +4515,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
// Prepare the new CD-ROM configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentVMCDROM) {
|
||||
cdromBlock, err := getSchemaBlock(
|
||||
cdromBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMCDROM},
|
||||
@ -4564,7 +4566,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
// Prepare the new CPU configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentVMCPU) {
|
||||
cpuBlock, err := getSchemaBlock(
|
||||
cpuBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMCPU},
|
||||
@ -4726,7 +4728,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
// Prepare the new memory configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentVMMemory) {
|
||||
memoryBlock, err := getSchemaBlock(
|
||||
memoryBlock, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMMemory},
|
||||
@ -4775,7 +4777,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
// Prepare the new operating system configuration.
|
||||
if d.HasChange(mkResourceVirtualEnvironmentVMOperatingSystem) {
|
||||
operatingSystem, err := getSchemaBlock(
|
||||
operatingSystem, err := structure.GetSchemaBlock(
|
||||
resource,
|
||||
d,
|
||||
[]string{mkResourceVirtualEnvironmentVMOperatingSystem},
|
||||
@ -5112,3 +5114,138 @@ func vmDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func diskDigitPrefix(s string) string {
|
||||
for i, r := range s {
|
||||
if unicode.IsDigit(r) {
|
||||
return s[:i]
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func getDiskInfo(resp *vms.GetResponseData, d *schema.ResourceData) map[string]*vms.CustomStorageDevice {
|
||||
currentDisk := d.Get(mkResourceVirtualEnvironmentVMDisk)
|
||||
|
||||
currentDiskList := currentDisk.([]interface{})
|
||||
currentDiskMap := map[string]map[string]interface{}{}
|
||||
|
||||
for _, v := range currentDiskList {
|
||||
diskMap := v.(map[string]interface{})
|
||||
diskInterface := diskMap[mkResourceVirtualEnvironmentVMDiskInterface].(string)
|
||||
|
||||
currentDiskMap[diskInterface] = diskMap
|
||||
}
|
||||
|
||||
storageDevices := map[string]*vms.CustomStorageDevice{}
|
||||
|
||||
storageDevices["ide0"] = resp.IDEDevice0
|
||||
storageDevices["ide1"] = resp.IDEDevice1
|
||||
storageDevices["ide2"] = resp.IDEDevice2
|
||||
storageDevices["ide3"] = resp.IDEDevice3
|
||||
|
||||
storageDevices["sata0"] = resp.SATADevice0
|
||||
storageDevices["sata1"] = resp.SATADevice1
|
||||
storageDevices["sata2"] = resp.SATADevice2
|
||||
storageDevices["sata3"] = resp.SATADevice3
|
||||
storageDevices["sata4"] = resp.SATADevice4
|
||||
storageDevices["sata5"] = resp.SATADevice5
|
||||
|
||||
storageDevices["scsi0"] = resp.SCSIDevice0
|
||||
storageDevices["scsi1"] = resp.SCSIDevice1
|
||||
storageDevices["scsi2"] = resp.SCSIDevice2
|
||||
storageDevices["scsi3"] = resp.SCSIDevice3
|
||||
storageDevices["scsi4"] = resp.SCSIDevice4
|
||||
storageDevices["scsi5"] = resp.SCSIDevice5
|
||||
storageDevices["scsi6"] = resp.SCSIDevice6
|
||||
storageDevices["scsi7"] = resp.SCSIDevice7
|
||||
storageDevices["scsi8"] = resp.SCSIDevice8
|
||||
storageDevices["scsi9"] = resp.SCSIDevice9
|
||||
storageDevices["scsi10"] = resp.SCSIDevice10
|
||||
storageDevices["scsi11"] = resp.SCSIDevice11
|
||||
storageDevices["scsi12"] = resp.SCSIDevice12
|
||||
storageDevices["scsi13"] = resp.SCSIDevice13
|
||||
|
||||
storageDevices["virtio0"] = resp.VirtualIODevice0
|
||||
storageDevices["virtio1"] = resp.VirtualIODevice1
|
||||
storageDevices["virtio2"] = resp.VirtualIODevice2
|
||||
storageDevices["virtio3"] = resp.VirtualIODevice3
|
||||
storageDevices["virtio4"] = resp.VirtualIODevice4
|
||||
storageDevices["virtio5"] = resp.VirtualIODevice5
|
||||
storageDevices["virtio6"] = resp.VirtualIODevice6
|
||||
storageDevices["virtio7"] = resp.VirtualIODevice7
|
||||
storageDevices["virtio8"] = resp.VirtualIODevice8
|
||||
storageDevices["virtio9"] = resp.VirtualIODevice9
|
||||
storageDevices["virtio10"] = resp.VirtualIODevice10
|
||||
storageDevices["virtio11"] = resp.VirtualIODevice11
|
||||
storageDevices["virtio12"] = resp.VirtualIODevice12
|
||||
storageDevices["virtio13"] = resp.VirtualIODevice13
|
||||
storageDevices["virtio14"] = resp.VirtualIODevice14
|
||||
storageDevices["virtio15"] = resp.VirtualIODevice15
|
||||
|
||||
for k, v := range storageDevices {
|
||||
if v != nil {
|
||||
if currentDiskMap[k] != nil {
|
||||
if currentDiskMap[k][mkResourceVirtualEnvironmentVMDiskFileID] != nil {
|
||||
fileID := currentDiskMap[k][mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
v.FileID = &fileID
|
||||
}
|
||||
}
|
||||
// defensive copy of the loop variable
|
||||
iface := k
|
||||
v.Interface = &iface
|
||||
}
|
||||
}
|
||||
|
||||
return storageDevices
|
||||
}
|
||||
|
||||
// getDiskDatastores returns a list of the used datastores in a VM.
|
||||
func getDiskDatastores(vm *vms.GetResponseData, d *schema.ResourceData) []string {
|
||||
storageDevices := getDiskInfo(vm, d)
|
||||
datastoresSet := map[string]int{}
|
||||
|
||||
for _, diskInfo := range storageDevices {
|
||||
// Ignore empty storage devices and storage devices (like ide) which may not have any media mounted
|
||||
if diskInfo == nil || diskInfo.FileVolume == "none" {
|
||||
continue
|
||||
}
|
||||
|
||||
fileIDParts := strings.Split(diskInfo.FileVolume, ":")
|
||||
datastoresSet[fileIDParts[0]] = 1
|
||||
}
|
||||
|
||||
if vm.EFIDisk != nil {
|
||||
fileIDParts := strings.Split(vm.EFIDisk.FileVolume, ":")
|
||||
datastoresSet[fileIDParts[0]] = 1
|
||||
}
|
||||
|
||||
datastores := []string{}
|
||||
for datastore := range datastoresSet {
|
||||
datastores = append(datastores, datastore)
|
||||
}
|
||||
|
||||
return datastores
|
||||
}
|
||||
|
||||
func getPCIInfo(resp *vms.GetResponseData, _ *schema.ResourceData) map[string]*vms.CustomPCIDevice {
|
||||
pciDevices := map[string]*vms.CustomPCIDevice{}
|
||||
|
||||
pciDevices["hostpci0"] = resp.PCIDevice0
|
||||
pciDevices["hostpci1"] = resp.PCIDevice1
|
||||
pciDevices["hostpci2"] = resp.PCIDevice2
|
||||
pciDevices["hostpci3"] = resp.PCIDevice3
|
||||
|
||||
return pciDevices
|
||||
}
|
||||
|
||||
func parseImportIDWithNodeName(id string) (string, string, error) {
|
||||
nodeName, id, found := strings.Cut(id, "/")
|
||||
|
||||
if !found {
|
||||
return "", "", fmt.Errorf("unexpected format of ID (%s), expected node/id", id)
|
||||
}
|
||||
|
||||
return nodeName, id, nil
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
|
||||
)
|
||||
@ -437,3 +438,38 @@ func TestVMSchema(t *testing.T) {
|
||||
mkResourceVirtualEnvironmentVMVGAType: schema.TypeString,
|
||||
})
|
||||
}
|
||||
|
||||
func Test_parseImportIDWIthNodeName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
valid bool
|
||||
expectedNodeName string
|
||||
expectedID string
|
||||
}{
|
||||
{"empty", "", false, "", ""},
|
||||
{"missing slash", "invalid", false, "", ""},
|
||||
{"valid", "host/id", true, "host", "id"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
nodeName, id, err := parseImportIDWithNodeName(tt.value)
|
||||
|
||||
if !tt.valid {
|
||||
require.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
require.Nil(err)
|
||||
require.Equal(tt.expectedNodeName, nodeName)
|
||||
require.Equal(tt.expectedID, id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
122
proxmoxtf/structure/schema.go
Normal file
122
proxmoxtf/structure/schema.go
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package structure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
// MergeSchema merges the map[string]*schema.Schema from src into dst. Safety
|
||||
// against conflicts is enforced by panicking.
|
||||
func MergeSchema(dst, src map[string]*schema.Schema) {
|
||||
for k, v := range src {
|
||||
if _, ok := dst[k]; ok {
|
||||
panic(fmt.Errorf("conflicting schema key: %s", k))
|
||||
}
|
||||
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetSchemaBlock returns a map[string]interface{} of a nested resource by key(s) from a schema.ResourceData.
|
||||
func GetSchemaBlock(
|
||||
r *schema.Resource,
|
||||
d *schema.ResourceData,
|
||||
k []string,
|
||||
i int,
|
||||
allowDefault bool,
|
||||
) (map[string]interface{}, error) {
|
||||
var resourceBlock map[string]interface{}
|
||||
|
||||
var resourceData interface{}
|
||||
|
||||
var resourceSchema *schema.Schema
|
||||
|
||||
for ki, kv := range k {
|
||||
if ki == 0 {
|
||||
resourceData = d.Get(kv)
|
||||
resourceSchema = r.Schema[kv]
|
||||
} else {
|
||||
mapValues := resourceData.([]interface{})
|
||||
|
||||
if len(mapValues) <= i {
|
||||
return resourceBlock, fmt.Errorf("index out of bounds %d", i)
|
||||
}
|
||||
|
||||
mapValue := mapValues[i].(map[string]interface{})
|
||||
|
||||
resourceData = mapValue[kv]
|
||||
resourceSchema = resourceSchema.Elem.(*schema.Resource).Schema[kv]
|
||||
}
|
||||
}
|
||||
|
||||
list := resourceData.([]interface{})
|
||||
|
||||
if len(list) == 0 {
|
||||
if allowDefault {
|
||||
listDefault, err := resourceSchema.DefaultValue()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get default value for %s: %w", strings.Join(k, "."), err)
|
||||
}
|
||||
|
||||
list = listDefault.([]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if len(list) > i {
|
||||
resourceBlock = list[i].(map[string]interface{})
|
||||
}
|
||||
|
||||
return resourceBlock, nil
|
||||
}
|
||||
|
||||
// SuppressIfListsAreEqualIgnoringOrder is a customdiff.SuppressionFunc that suppresses
|
||||
// changes to a list if the old and new lists are equal, ignoring the order of the
|
||||
// elements.
|
||||
// It will be called for each list item, so it is not super efficient. It is
|
||||
// recommended to use it only for small lists.
|
||||
// Ref: https://github.com/hashicorp/terraform-plugin-sdk/issues/477
|
||||
func SuppressIfListsAreEqualIgnoringOrder(key, _, _ string, d *schema.ResourceData) bool {
|
||||
// the key is a path to the list item, not the list itself, e.g. "tags.0"
|
||||
lastDotIndex := strings.LastIndex(key, ".")
|
||||
if lastDotIndex != -1 {
|
||||
key = key[:lastDotIndex]
|
||||
}
|
||||
|
||||
oldData, newData := d.GetChange(key)
|
||||
if oldData == nil || newData == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
oldArray := oldData.([]interface{})
|
||||
newArray := newData.([]interface{})
|
||||
|
||||
if len(oldArray) != len(newArray) {
|
||||
return false
|
||||
}
|
||||
|
||||
oldEvents := make([]string, len(oldArray))
|
||||
newEvents := make([]string, len(newArray))
|
||||
|
||||
for i, oldEvt := range oldArray {
|
||||
oldEvents[i] = fmt.Sprint(oldEvt)
|
||||
}
|
||||
|
||||
for j, newEvt := range newArray {
|
||||
newEvents[j] = fmt.Sprint(newEvt)
|
||||
}
|
||||
|
||||
sort.Strings(oldEvents)
|
||||
sort.Strings(newEvents)
|
||||
|
||||
return reflect.DeepEqual(oldEvents, newEvents)
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package structure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// AssertComputedAttributes asserts that the given keys are present in the schema and are computed.
|
||||
func AssertComputedAttributes(t *testing.T, s map[string]*schema.Schema, keys []string) {
|
||||
t.Helper()
|
||||
|
||||
for _, v := range keys {
|
||||
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 asserts that the given key is present in the schema and is a nested schema.
|
||||
func AssertNestedSchemaExistence(t *testing.T, s map[string]*schema.Schema, key string) *schema.Resource {
|
||||
t.Helper()
|
||||
|
||||
sh, ok := s[key].Elem.(*schema.Resource)
|
||||
|
||||
if !ok {
|
||||
t.Fatalf("Error in Schema: Missing nested schema for \"%s\"", key)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return sh
|
||||
}
|
||||
|
||||
// AssertOptionalArguments asserts that the given keys are present in the schema and are optional.
|
||||
func AssertOptionalArguments(t *testing.T, s map[string]*schema.Schema, keys []string) {
|
||||
t.Helper()
|
||||
|
||||
for _, v := range keys {
|
||||
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 asserts that the given keys are present in the schema and are required.
|
||||
func AssertRequiredArguments(t *testing.T, s map[string]*schema.Schema, keys []string) {
|
||||
t.Helper()
|
||||
|
||||
for _, v := range keys {
|
||||
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 asserts that the given keys are present in the schema and are of the given type.
|
||||
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[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)
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package structure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
// MergeSchema merges the map[string]*schema.Schema from src into dst. Safety
|
||||
// against conflicts is enforced by panicking.
|
||||
func MergeSchema(dst, src map[string]*schema.Schema) {
|
||||
for k, v := range src {
|
||||
if _, ok := dst[k]; ok {
|
||||
panic(fmt.Errorf("conflicting schema key: %s", k))
|
||||
}
|
||||
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user