0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-09 15:25:01 +00:00

messing with disks

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2024-02-01 23:43:43 -05:00
parent f04b729db2
commit 5bf5754cb3
No known key found for this signature in database
GPG Key ID: 02A24794ADAC7455
7 changed files with 2468 additions and 2382 deletions

View File

@ -1,9 +1,13 @@
{
"git.alwaysSignOff": true,
"cSpell.words": [
"Burstable",
"cdrom",
"CLRF",
"iothread",
"keyctl",
"mbps",
"NUMA",
"proxmoxtf",
"qcow",
"rootfs",

View File

@ -8,15 +8,15 @@ import (
)
func createAgent(d *schema.ResourceData, updateBody *vms.UpdateRequestBody) {
agent := d.Get(mkResourceVirtualEnvironmentVMAgent).([]interface{})
agent := d.Get(mkAgent).([]interface{})
if len(agent) > 0 {
agentBlock := agent[0].(map[string]interface{})
agentEnabled := types.CustomBool(
agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool),
agentBlock[mkAgentEnabled].(bool),
)
agentTrim := types.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
agentTrim := types.CustomBool(agentBlock[mkAgentTrim].(bool))
agentType := agentBlock[mkAgentType].(string)
updateBody.Agent = &vms.CustomAgent{
Enabled: &agentEnabled,
@ -30,7 +30,7 @@ func customAgent(d *schema.ResourceData, resource *schema.Resource) (*vms.Custom
agentBlock, err := structure.GetSchemaBlock(
resource,
d,
[]string{mkResourceVirtualEnvironmentVMAgent},
[]string{mkAgent},
0,
true,
)
@ -39,10 +39,10 @@ func customAgent(d *schema.ResourceData, resource *schema.Resource) (*vms.Custom
}
agentEnabled := types.CustomBool(
agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool),
agentBlock[mkAgentEnabled].(bool),
)
agentTrim := types.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
agentTrim := types.CustomBool(agentBlock[mkAgentTrim].(bool))
agentType := agentBlock[mkAgentType].(string)
return &vms.CustomAgent{
Enabled: &agentEnabled,
@ -53,64 +53,64 @@ func customAgent(d *schema.ResourceData, resource *schema.Resource) (*vms.Custom
func setAgent(d *schema.ResourceData, clone bool, vmConfig *vms.GetResponseData) error {
// Compare the agent configuration to the one stored in the state.
currentAgent := d.Get(mkResourceVirtualEnvironmentVMAgent).([]interface{})
currentAgent := d.Get(mkAgent).([]interface{})
if !clone || len(currentAgent) > 0 {
if vmConfig.Agent != nil {
agent := map[string]interface{}{}
if vmConfig.Agent.Enabled != nil {
agent[mkResourceVirtualEnvironmentVMAgentEnabled] = bool(*vmConfig.Agent.Enabled)
agent[mkAgentEnabled] = bool(*vmConfig.Agent.Enabled)
} else {
agent[mkResourceVirtualEnvironmentVMAgentEnabled] = false
agent[mkAgentEnabled] = false
}
if vmConfig.Agent.TrimClonedDisks != nil {
agent[mkResourceVirtualEnvironmentVMAgentTrim] = bool(
agent[mkAgentTrim] = bool(
*vmConfig.Agent.TrimClonedDisks,
)
} else {
agent[mkResourceVirtualEnvironmentVMAgentTrim] = false
agent[mkAgentTrim] = false
}
if len(currentAgent) > 0 {
currentAgentBlock := currentAgent[0].(map[string]interface{})
currentAgentTimeout := currentAgentBlock[mkResourceVirtualEnvironmentVMAgentTimeout].(string)
currentAgentTimeout := currentAgentBlock[mkAgentTimeout].(string)
if currentAgentTimeout != "" {
agent[mkResourceVirtualEnvironmentVMAgentTimeout] = currentAgentTimeout
agent[mkAgentTimeout] = currentAgentTimeout
} else {
agent[mkResourceVirtualEnvironmentVMAgentTimeout] = dvResourceVirtualEnvironmentVMAgentTimeout
agent[mkAgentTimeout] = dvAgentTimeout
}
} else {
agent[mkResourceVirtualEnvironmentVMAgentTimeout] = dvResourceVirtualEnvironmentVMAgentTimeout
agent[mkAgentTimeout] = dvAgentTimeout
}
if vmConfig.Agent.Type != nil {
agent[mkResourceVirtualEnvironmentVMAgentType] = *vmConfig.Agent.Type
agent[mkAgentType] = *vmConfig.Agent.Type
} else {
agent[mkResourceVirtualEnvironmentVMAgentType] = ""
agent[mkAgentType] = ""
}
if clone {
if len(currentAgent) > 0 {
return d.Set(mkResourceVirtualEnvironmentVMAgent, []interface{}{agent})
return d.Set(mkAgent, []interface{}{agent})
}
} else if len(currentAgent) > 0 ||
agent[mkResourceVirtualEnvironmentVMAgentEnabled] != dvResourceVirtualEnvironmentVMAgentEnabled ||
agent[mkResourceVirtualEnvironmentVMAgentTimeout] != dvResourceVirtualEnvironmentVMAgentTimeout ||
agent[mkResourceVirtualEnvironmentVMAgentTrim] != dvResourceVirtualEnvironmentVMAgentTrim ||
agent[mkResourceVirtualEnvironmentVMAgentType] != dvResourceVirtualEnvironmentVMAgentType {
return d.Set(mkResourceVirtualEnvironmentVMAgent, []interface{}{agent})
agent[mkAgentEnabled] != dvAgentEnabled ||
agent[mkAgentTimeout] != dvAgentTimeout ||
agent[mkAgentTrim] != dvAgentTrim ||
agent[mkAgentType] != dvAgentType {
return d.Set(mkAgent, []interface{}{agent})
}
} else if clone {
if len(currentAgent) > 0 {
return d.Set(mkResourceVirtualEnvironmentVMAgent, []interface{}{})
return d.Set(mkAgent, []interface{}{})
}
} else {
return d.Set(mkResourceVirtualEnvironmentVMAgent, []interface{}{})
return d.Set(mkAgent, []interface{}{})
}
}
return nil
}

View File

@ -0,0 +1,753 @@
package vm
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
func diskSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Description: "The disk devices",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return []interface{}{
map[string]interface{}{
mkDiskDatastoreID: dvDiskDatastoreID,
mkDiskPathInDatastore: nil,
mkDiskFileID: dvDiskFileID,
mkDiskInterface: dvDiskInterface,
mkDiskSize: dvDiskSize,
mkDiskIOThread: dvDiskIOThread,
mkDiskSSD: dvDiskSSD,
mkDiskDiscard: dvDiskDiscard,
mkDiskCache: dvDiskCache,
},
}, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkDiskInterface: {
Type: schema.TypeString,
Description: "The datastore name",
Required: true,
},
mkDiskDatastoreID: {
Type: schema.TypeString,
Description: "The datastore id",
Optional: true,
Default: dvDiskDatastoreID,
},
mkDiskPathInDatastore: {
Type: schema.TypeString,
Description: "The in-datastore path to disk image",
Computed: true,
Optional: true,
Default: nil,
},
mkDiskFileFormat: {
Type: schema.TypeString,
Description: "The file format",
Optional: true,
ForceNew: true,
Computed: true,
ValidateDiagFunc: validator.FileFormat(),
},
mkDiskFileID: {
Type: schema.TypeString,
Description: "The file id for a disk image",
Optional: true,
ForceNew: true,
Default: dvDiskFileID,
ValidateDiagFunc: validator.FileID(),
},
mkDiskSize: {
Type: schema.TypeInt,
Description: "The disk size in gigabytes",
Optional: true,
Default: dvDiskSize,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),
},
mkDiskIOThread: {
Type: schema.TypeBool,
Description: "Whether to use iothreads for this disk drive",
Optional: true,
Default: dvDiskIOThread,
},
mkDiskSSD: {
Type: schema.TypeBool,
Description: "Whether to use ssd for this disk drive",
Optional: true,
Default: dvDiskSSD,
},
mkDiskDiscard: {
Type: schema.TypeString,
Description: "Whether to pass discard/trim requests to the underlying storage.",
Optional: true,
Default: dvDiskDiscard,
},
mkDiskCache: {
Type: schema.TypeString,
Description: "The drives cache mode",
Optional: true,
Default: dvDiskCache,
ValidateDiagFunc: validation.ToDiagFunc(
validation.StringInSlice([]string{
"none",
"writethrough",
"writeback",
"unsafe",
"directsync",
}, false),
),
},
mkDiskSpeed: {
Type: schema.TypeList,
Description: "The speed limits",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return []interface{}{
map[string]interface{}{
mkDiskSpeedRead: dvDiskSpeedRead,
mkDiskSpeedReadBurstable: dvDiskSpeedReadBurstable,
mkDiskSpeedWrite: dvDiskSpeedWrite,
mkDiskSpeedWriteBurstable: dvDiskSpeedWriteBurstable,
},
}, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkDiskSpeedRead: {
Type: schema.TypeInt,
Description: "The maximum read speed in megabytes per second",
Optional: true,
Default: dvDiskSpeedRead,
},
mkDiskSpeedReadBurstable: {
Type: schema.TypeInt,
Description: "The maximum burstable read speed in megabytes per second",
Optional: true,
Default: dvDiskSpeedReadBurstable,
},
mkDiskSpeedWrite: {
Type: schema.TypeInt,
Description: "The maximum write speed in megabytes per second",
Optional: true,
Default: dvDiskSpeedWrite,
},
mkDiskSpeedWriteBurstable: {
Type: schema.TypeInt,
Description: "The maximum burstable write speed in megabytes per second",
Optional: true,
Default: dvDiskSpeedWriteBurstable,
},
},
},
MaxItems: 1,
MinItems: 0,
},
},
},
}
}
func updateDisk1(
ctx context.Context, vmConfig *vms.GetResponseData, d *schema.ResourceData, vmAPI *vms.Client,
) (map[string]*vms.CustomStorageDevice, error) {
allDiskInfo := getDiskInfo(vmConfig, d)
diskDeviceObjects, e := vmGetDiskDeviceObjects(d, nil)
if e != nil {
return nil, e
}
disk := d.Get(mkDisk).([]interface{})
for i := range disk {
diskBlock := disk[i].(map[string]interface{})
diskInterface := diskBlock[mkDiskInterface].(string)
dataStoreID := diskBlock[mkDiskDatastoreID].(string)
diskSize := int64(diskBlock[mkDiskSize].(int))
prefix := diskDigitPrefix(diskInterface)
currentDiskInfo := allDiskInfo[diskInterface]
configuredDiskInfo := diskDeviceObjects[prefix][diskInterface]
if currentDiskInfo == nil {
diskUpdateBody := &vms.UpdateRequestBody{}
switch prefix {
case "virtio":
if diskUpdateBody.VirtualIODevices == nil {
diskUpdateBody.VirtualIODevices = vms.CustomStorageDevices{}
}
diskUpdateBody.VirtualIODevices[diskInterface] = configuredDiskInfo
case "sata":
if diskUpdateBody.SATADevices == nil {
diskUpdateBody.SATADevices = vms.CustomStorageDevices{}
}
diskUpdateBody.SATADevices[diskInterface] = configuredDiskInfo
case "scsi":
if diskUpdateBody.SCSIDevices == nil {
diskUpdateBody.SCSIDevices = vms.CustomStorageDevices{}
}
diskUpdateBody.SCSIDevices[diskInterface] = configuredDiskInfo
}
e = vmAPI.UpdateVM(ctx, diskUpdateBody)
if e != nil {
return nil, e
}
continue
}
if diskSize < currentDiskInfo.Size.InGigabytes() {
return nil, fmt.Errorf("disk resize fails requests size (%dG) is lower than current size (%s)",
diskSize,
*currentDiskInfo.Size,
)
}
deleteOriginalDisk := types.CustomBool(true)
diskMoveBody := &vms.MoveDiskRequestBody{
DeleteOriginalDisk: &deleteOriginalDisk,
Disk: diskInterface,
TargetStorage: dataStoreID,
}
diskResizeBody := &vms.ResizeDiskRequestBody{
Disk: diskInterface,
Size: types.DiskSizeFromGigabytes(diskSize),
}
moveDisk := false
if dataStoreID != "" {
moveDisk = true
if allDiskInfo[diskInterface] != nil {
fileIDParts := strings.Split(allDiskInfo[diskInterface].FileVolume, ":")
moveDisk = dataStoreID != fileIDParts[0]
}
}
if moveDisk {
moveDiskTimeout := d.Get(mkTimeoutMoveDisk).(int)
e = vmAPI.MoveVMDisk(ctx, diskMoveBody, moveDiskTimeout)
if e != nil {
return nil, e
}
}
if diskSize > currentDiskInfo.Size.InGigabytes() {
e = vmAPI.ResizeVMDisk(ctx, diskResizeBody)
if e != nil {
return nil, e
}
}
}
return allDiskInfo, nil
}
func vmCreateCustomDisks(ctx context.Context, d *schema.ResourceData, m interface{}) error {
vmID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}
// Determine the ID of the next disk.
disk := d.Get(mkDisk).([]interface{})
diskCount := 0
for _, d := range disk {
block := d.(map[string]interface{})
fileID, _ := block[mkDiskFileID].(string)
if fileID == "" {
diskCount++
}
}
// Retrieve some information about the disk schema.
resourceSchema := VM().Schema
diskSchemaElem := resourceSchema[mkDisk].Elem
diskSchemaResource := diskSchemaElem.(*schema.Resource)
diskSpeedResource := diskSchemaResource.Schema[mkDiskSpeed]
// Generate the commands required to import the specified disks.
commands := []string{}
importedDiskCount := 0
for _, d := range disk {
block := d.(map[string]interface{})
fileID, _ := block[mkDiskFileID].(string)
if fileID == "" {
continue
}
datastoreID, _ := block[mkDiskDatastoreID].(string)
fileFormat, _ := block[mkDiskFileFormat].(string)
size, _ := block[mkDiskSize].(int)
speed := block[mkDiskSpeed].([]interface{})
diskInterface, _ := block[mkDiskInterface].(string)
ioThread := types.CustomBool(block[mkDiskIOThread].(bool))
ssd := types.CustomBool(block[mkDiskSSD].(bool))
discard, _ := block[mkDiskDiscard].(string)
cache, _ := block[mkDiskCache].(string)
if fileFormat == "" {
fileFormat = dvDiskFileFormat
}
if len(speed) == 0 {
diskSpeedDefault, err := diskSpeedResource.DefaultValue()
if err != nil {
return err
}
speed = diskSpeedDefault.([]interface{})
}
speedBlock := speed[0].(map[string]interface{})
speedLimitRead := speedBlock[mkDiskSpeedRead].(int)
speedLimitReadBurstable := speedBlock[mkDiskSpeedReadBurstable].(int)
speedLimitWrite := speedBlock[mkDiskSpeedWrite].(int)
speedLimitWriteBurstable := speedBlock[mkDiskSpeedWriteBurstable].(int)
diskOptions := ""
if ioThread {
diskOptions += ",iothread=1"
}
if ssd {
diskOptions += ",ssd=1"
}
if discard != "" {
diskOptions += fmt.Sprintf(",discard=%s", discard)
}
if cache != "" {
diskOptions += fmt.Sprintf(",cache=%s", cache)
}
if speedLimitRead > 0 {
diskOptions += fmt.Sprintf(",mbps_rd=%d", speedLimitRead)
}
if speedLimitReadBurstable > 0 {
diskOptions += fmt.Sprintf(",mbps_rd_max=%d", speedLimitReadBurstable)
}
if speedLimitWrite > 0 {
diskOptions += fmt.Sprintf(",mbps_wr=%d", speedLimitWrite)
}
if speedLimitWriteBurstable > 0 {
diskOptions += fmt.Sprintf(",mbps_wr_max=%d", speedLimitWriteBurstable)
}
filePathTmp := fmt.Sprintf(
"/tmp/vm-%d-disk-%d.%s",
vmID,
diskCount+importedDiskCount,
fileFormat,
)
//nolint:lll
commands = append(
commands,
`set -e`,
`try_sudo(){ if [ $(sudo -n echo tfpve 2>&1 | grep "tfpve" | wc -l) -gt 0 ]; then sudo $1; else $1; fi }`,
fmt.Sprintf(`file_id="%s"`, fileID),
fmt.Sprintf(`file_format="%s"`, fileFormat),
fmt.Sprintf(`datastore_id_target="%s"`, datastoreID),
fmt.Sprintf(`disk_options="%s"`, diskOptions),
fmt.Sprintf(`disk_size="%d"`, size),
fmt.Sprintf(`disk_interface="%s"`, diskInterface),
fmt.Sprintf(`file_path_tmp="%s"`, filePathTmp),
fmt.Sprintf(`vm_id="%d"`, vmID),
`source_image=$(try_sudo "pvesm path $file_id")`,
`imported_disk="$(try_sudo "qm importdisk $vm_id $source_image $datastore_id_target -format $file_format" | grep "unused0" | cut -d ":" -f 3 | cut -d "'" -f 1)"`,
`disk_id="${datastore_id_target}:$imported_disk${disk_options}"`,
`try_sudo "qm set $vm_id -${disk_interface} $disk_id"`,
`try_sudo "qm resize $vm_id ${disk_interface} ${disk_size}G"`,
)
importedDiskCount++
}
// Execute the commands on the node and wait for the result.
// This is a highly experimental approach to disk imports and is not recommended by Proxmox.
if len(commands) > 0 {
config := m.(proxmoxtf.ProviderConfiguration)
api, err := config.GetClient()
if err != nil {
return err
}
nodeName := d.Get(mkNodeName).(string)
out, err := api.SSH().ExecuteNodeCommands(ctx, nodeName, commands)
if err != nil {
if strings.Contains(err.Error(), "pvesm: not found") {
return fmt.Errorf("The configured SSH user '%s' does not have the required permissions to import disks. "+
"Make sure `sudo` is installed and the user is a member of sudoers.", api.SSH().Username())
}
return err
}
tflog.Debug(ctx, "vmCreateCustomDisks", map[string]interface{}{
"output": string(out),
})
}
return nil
}
func vmGetDiskDeviceObjects(
d *schema.ResourceData,
disks []interface{},
) (map[string]map[string]vms.CustomStorageDevice, error) {
var diskDevice []interface{}
if disks != nil {
diskDevice = disks
} else {
diskDevice = d.Get(mkDisk).([]interface{})
}
diskDeviceObjects := map[string]map[string]vms.CustomStorageDevice{}
resource := VM()
for _, diskEntry := range diskDevice {
diskDevice := vms.CustomStorageDevice{
Enabled: true,
}
block := diskEntry.(map[string]interface{})
datastoreID, _ := block[mkDiskDatastoreID].(string)
pathInDatastore := ""
if untyped, hasPathInDatastore := block[mkDiskPathInDatastore]; hasPathInDatastore {
pathInDatastore = untyped.(string)
}
fileFormat, _ := block[mkDiskFileFormat].(string)
fileID, _ := block[mkDiskFileID].(string)
size, _ := block[mkDiskSize].(int)
diskInterface, _ := block[mkDiskInterface].(string)
ioThread := types.CustomBool(block[mkDiskIOThread].(bool))
ssd := types.CustomBool(block[mkDiskSSD].(bool))
discard := block[mkDiskDiscard].(string)
cache := block[mkDiskCache].(string)
speedBlock, err := structure.GetSchemaBlock(
resource,
d,
[]string{mkDisk, mkDiskSpeed},
0,
false,
)
if err != nil {
return diskDeviceObjects, err
}
if fileFormat == "" {
fileFormat = dvDiskFileFormat
}
if fileID != "" {
diskDevice.Enabled = false
}
if pathInDatastore != "" {
if datastoreID != "" {
diskDevice.FileVolume = fmt.Sprintf("%s:%s", datastoreID, pathInDatastore)
} else {
// FileVolume is absolute path in the host filesystem
diskDevice.FileVolume = pathInDatastore
}
} else {
diskDevice.FileVolume = fmt.Sprintf("%s:%d", datastoreID, size)
}
diskDevice.ID = &datastoreID
diskDevice.Interface = &diskInterface
diskDevice.Format = &fileFormat
diskDevice.FileID = &fileID
diskSize := types.DiskSizeFromGigabytes(int64(size))
diskDevice.Size = &diskSize
diskDevice.IOThread = &ioThread
diskDevice.Discard = &discard
diskDevice.Cache = &cache
if !strings.HasPrefix(diskInterface, "virtio") {
diskDevice.SSD = &ssd
}
if len(speedBlock) > 0 {
speedLimitRead := speedBlock[mkDiskSpeedRead].(int)
speedLimitReadBurstable := speedBlock[mkDiskSpeedReadBurstable].(int)
speedLimitWrite := speedBlock[mkDiskSpeedWrite].(int)
speedLimitWriteBurstable := speedBlock[mkDiskSpeedWriteBurstable].(int)
if speedLimitRead > 0 {
diskDevice.MaxReadSpeedMbps = &speedLimitRead
}
if speedLimitReadBurstable > 0 {
diskDevice.BurstableReadSpeedMbps = &speedLimitReadBurstable
}
if speedLimitWrite > 0 {
diskDevice.MaxWriteSpeedMbps = &speedLimitWrite
}
if speedLimitWriteBurstable > 0 {
diskDevice.BurstableWriteSpeedMbps = &speedLimitWriteBurstable
}
}
baseDiskInterface := diskDigitPrefix(diskInterface)
if baseDiskInterface != "virtio" && baseDiskInterface != "scsi" &&
baseDiskInterface != "sata" {
errorMsg := fmt.Sprintf(
"Defined disk interface not supported. Interface was %s, but only virtio, sata and scsi are supported",
diskInterface,
)
return diskDeviceObjects, errors.New(errorMsg)
}
if _, present := diskDeviceObjects[baseDiskInterface]; !present {
diskDeviceObjects[baseDiskInterface] = map[string]vms.CustomStorageDevice{}
}
diskDeviceObjects[baseDiskInterface][diskInterface] = diskDevice
}
return diskDeviceObjects, nil
}
func readDisk1(ctx context.Context, d *schema.ResourceData,
vmConfig *vms.GetResponseData, vmID int, api proxmox.Client, nodeName string, clone []interface{},
) diag.Diagnostics {
currentDiskList := d.Get(mkDisk).([]interface{})
diskMap := map[string]interface{}{}
diskObjects := getDiskInfo(vmConfig, d)
var diags diag.Diagnostics
for di, dd := range diskObjects {
if dd == nil || dd.FileVolume == "none" || strings.HasPrefix(di, "ide") {
continue
}
if dd.IsCloudInitDrive(vmID) {
continue
}
disk := map[string]interface{}{}
datastoreID, pathInDatastore, hasDatastoreID := strings.Cut(dd.FileVolume, ":")
if !hasDatastoreID {
// when no ':' separator is found, 'Cut' places the whole string to 'datastoreID',
// we want it in 'pathInDatastore' (it is absolute filesystem path)
pathInDatastore = datastoreID
datastoreID = ""
}
disk[mkDiskDatastoreID] = datastoreID
disk[mkDiskPathInDatastore] = pathInDatastore
if dd.Format == nil {
disk[mkDiskFileFormat] = dvDiskFileFormat
if datastoreID != "" {
// 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, err := api.Node(nodeName).Storage(datastoreID).GetDatastoreFile(ctx, dd.FileVolume)
if err != nil {
diags = append(diags, diag.FromErr(err)...)
continue
}
disk[mkDiskFileFormat] = volume.FileFormat
}
} else {
disk[mkDiskFileFormat] = dd.Format
}
if dd.FileID != nil {
disk[mkDiskFileID] = dd.FileID
}
disk[mkDiskInterface] = di
disk[mkDiskSize] = dd.Size.InGigabytes()
if dd.BurstableReadSpeedMbps != nil ||
dd.BurstableWriteSpeedMbps != nil ||
dd.MaxReadSpeedMbps != nil ||
dd.MaxWriteSpeedMbps != nil {
speed := map[string]interface{}{}
if dd.MaxReadSpeedMbps != nil {
speed[mkDiskSpeedRead] = *dd.MaxReadSpeedMbps
} else {
speed[mkDiskSpeedRead] = 0
}
if dd.BurstableReadSpeedMbps != nil {
speed[mkDiskSpeedReadBurstable] = *dd.BurstableReadSpeedMbps
} else {
speed[mkDiskSpeedReadBurstable] = 0
}
if dd.MaxWriteSpeedMbps != nil {
speed[mkDiskSpeedWrite] = *dd.MaxWriteSpeedMbps
} else {
speed[mkDiskSpeedWrite] = 0
}
if dd.BurstableWriteSpeedMbps != nil {
speed[mkDiskSpeedWriteBurstable] = *dd.BurstableWriteSpeedMbps
} else {
speed[mkDiskSpeedWriteBurstable] = 0
}
disk[mkDiskSpeed] = []interface{}{speed}
} else {
disk[mkDiskSpeed] = []interface{}{}
}
if dd.IOThread != nil {
disk[mkDiskIOThread] = *dd.IOThread
} else {
disk[mkDiskIOThread] = false
}
if dd.SSD != nil {
disk[mkDiskSSD] = *dd.SSD
} else {
disk[mkDiskSSD] = false
}
if dd.Discard != nil {
disk[mkDiskDiscard] = *dd.Discard
} else {
disk[mkDiskDiscard] = dvDiskDiscard
}
if dd.Cache != nil {
disk[mkDiskCache] = *dd.Cache
} else {
disk[mkDiskCache] = dvDiskCache
}
diskMap[di] = disk
}
if len(clone) == 0 || len(currentDiskList) > 0 {
orderedDiskList := orderedListFromMap(diskMap)
err := d.Set(mkDisk, orderedDiskList)
diags = append(diags, diag.FromErr(err)...)
}
return diags
}
func updateDisk(d *schema.ResourceData, vmConfig *vms.GetResponseData, updateBody *vms.UpdateRequestBody) error {
// Prepare the new disk device configuration.
if !d.HasChange(mkDisk) {
return nil
}
diskDeviceObjects, err := vmGetDiskDeviceObjects(d, nil)
if err != nil {
return err
}
diskDeviceInfo := getDiskInfo(vmConfig, d)
for prefix, diskMap := range diskDeviceObjects {
if diskMap == nil {
continue
}
for key, value := range diskMap {
if diskDeviceInfo[key] == nil {
// TODO: create a new disk here
return fmt.Errorf("missing %s device %s", prefix, key)
}
tmp := *diskDeviceInfo[key]
tmp.BurstableReadSpeedMbps = value.BurstableReadSpeedMbps
tmp.BurstableWriteSpeedMbps = value.BurstableWriteSpeedMbps
tmp.MaxReadSpeedMbps = value.MaxReadSpeedMbps
tmp.MaxWriteSpeedMbps = value.MaxWriteSpeedMbps
tmp.Cache = value.Cache
switch prefix {
case "virtio":
{
if updateBody.VirtualIODevices == nil {
updateBody.VirtualIODevices = vms.CustomStorageDevices{}
}
updateBody.VirtualIODevices[key] = tmp
}
case "sata":
{
if updateBody.SATADevices == nil {
updateBody.SATADevices = vms.CustomStorageDevices{}
}
updateBody.SATADevices[key] = tmp
}
case "scsi":
{
if updateBody.SCSIDevices == nil {
updateBody.SCSIDevices = vms.CustomStorageDevices{}
}
updateBody.SCSIDevices[key] = tmp
}
case "ide":
{
// Investigate whether to support IDE mapping.
}
default:
return fmt.Errorf("device prefix %s not supported", prefix)
}
}
}
return nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,492 @@
/*
* 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 vm
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/stretchr/testify/require"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
)
// TestVMInstantiation tests whether the VM instance can be instantiated.
func TestVMInstantiation(t *testing.T) {
t.Parallel()
s := VM()
if s == nil {
t.Fatalf("Cannot instantiate VM")
}
}
// TestVMSchema tests the VM schema.
func TestVMSchema(t *testing.T) {
t.Parallel()
s := VM()
test.AssertRequiredArguments(t, s, []string{
mkNodeName,
})
test.AssertOptionalArguments(t, s, []string{
mkACPI,
mkAgent,
mkAudioDevice,
mkBIOS,
mkBootOrder,
mkCDROM,
mkClone,
mkCPU,
mkDescription,
mkDisk,
mkEFIDisk,
mkInitialization,
mkHostPCI,
mkHostUSB,
mkKeyboardLayout,
mkKVMArguments,
mkMachine,
mkMemory,
mkName,
mkNetworkDevice,
mkOperatingSystem,
mkPoolID,
mkSerialDevice,
mkStarted,
mkTabletDevice,
mkTemplate,
mkVMID,
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,
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,
})
agentSchema := test.AssertNestedSchemaExistence(t, s, mkAgent)
test.AssertOptionalArguments(t, agentSchema, []string{
mkAgentEnabled,
mkAgentTimeout,
mkAgentTrim,
mkAgentType,
})
test.AssertValueTypes(t, agentSchema, map[string]schema.ValueType{
mkAgentEnabled: schema.TypeBool,
mkAgentTrim: schema.TypeBool,
mkAgentType: schema.TypeString,
})
audioDeviceSchema := test.AssertNestedSchemaExistence(t, s, mkAudioDevice)
test.AssertOptionalArguments(t, audioDeviceSchema, []string{
mkAudioDeviceDevice,
mkAudioDeviceDriver,
})
test.AssertValueTypes(t, audioDeviceSchema, map[string]schema.ValueType{
mkAudioDeviceDevice: schema.TypeString,
mkAudioDeviceDriver: schema.TypeString,
})
cdromSchema := test.AssertNestedSchemaExistence(t, s, mkCDROM)
test.AssertOptionalArguments(t, cdromSchema, []string{
mkCDROMEnabled,
mkCDROMFileID,
})
test.AssertValueTypes(t, cdromSchema, map[string]schema.ValueType{
mkCDROMEnabled: schema.TypeBool,
mkCDROMFileID: schema.TypeString,
})
cloneSchema := test.AssertNestedSchemaExistence(t, s, mkClone)
test.AssertRequiredArguments(t, cloneSchema, []string{
mkCloneVMID,
})
test.AssertOptionalArguments(t, cloneSchema, []string{
mkCloneDatastoreID,
mkCloneNodeName,
})
test.AssertValueTypes(t, cloneSchema, map[string]schema.ValueType{
mkCloneDatastoreID: schema.TypeString,
mkCloneNodeName: schema.TypeString,
mkCloneVMID: schema.TypeInt,
})
cpuSchema := test.AssertNestedSchemaExistence(t, s, mkCPU)
test.AssertOptionalArguments(t, cpuSchema, []string{
mkCPUArchitecture,
mkCPUCores,
mkCPUFlags,
mkCPUHotplugged,
mkCPUNUMA,
mkCPUSockets,
mkCPUType,
mkCPUUnits,
})
test.AssertValueTypes(t, cpuSchema, map[string]schema.ValueType{
mkCPUArchitecture: schema.TypeString,
mkCPUCores: schema.TypeInt,
mkCPUFlags: schema.TypeList,
mkCPUHotplugged: schema.TypeInt,
mkCPUNUMA: schema.TypeBool,
mkCPUSockets: schema.TypeInt,
mkCPUType: schema.TypeString,
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{
mkEFIDiskDatastoreID,
mkEFIDiskFileFormat,
mkEFIDiskType,
})
test.AssertValueTypes(t, efiDiskSchema, map[string]schema.ValueType{
mkEFIDiskDatastoreID: schema.TypeString,
mkEFIDiskFileFormat: schema.TypeString,
mkEFIDiskType: schema.TypeString,
})
initializationSchema := test.AssertNestedSchemaExistence(
t,
s,
mkInitialization,
)
test.AssertOptionalArguments(t, initializationSchema, []string{
mkInitializationDatastoreID,
mkInitializationInterface,
mkInitializationDNS,
mkInitializationIPConfig,
mkInitializationUserAccount,
})
test.AssertValueTypes(t, initializationSchema, map[string]schema.ValueType{
mkInitializationDatastoreID: schema.TypeString,
mkInitializationInterface: schema.TypeString,
mkInitializationDNS: schema.TypeList,
mkInitializationIPConfig: schema.TypeList,
mkInitializationUserAccount: schema.TypeList,
})
hostPCISchema := test.AssertNestedSchemaExistence(t, s, mkHostPCI)
test.AssertOptionalArguments(t, hostPCISchema, []string{
mkHostPCIDeviceMDev,
mkHostPCIDevicePCIE,
mkHostPCIDeviceROMBAR,
mkHostPCIDeviceROMFile,
mkHostPCIDeviceXVGA,
})
test.AssertValueTypes(t, hostPCISchema, map[string]schema.ValueType{
mkHostPCIDevice: schema.TypeString,
mkHostPCIDeviceMDev: schema.TypeString,
mkHostPCIDevicePCIE: schema.TypeBool,
mkHostPCIDeviceROMBAR: schema.TypeBool,
mkHostPCIDeviceROMFile: schema.TypeString,
mkHostPCIDeviceXVGA: schema.TypeBool,
})
hostUSBSchema := test.AssertNestedSchemaExistence(t, s, mkHostUSB)
test.AssertOptionalArguments(t, hostUSBSchema, []string{
mkHostUSBDeviceMapping,
})
test.AssertValueTypes(t, hostUSBSchema, map[string]schema.ValueType{
mkHostUSBDevice: schema.TypeString,
mkHostUSBDeviceUSB3: schema.TypeBool,
})
initializationDNSSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkInitializationDNS,
)
test.AssertOptionalArguments(t, initializationDNSSchema, []string{
mkInitializationDNSDomain,
mkInitializationDNSServer,
mkInitializationDNSServers,
})
test.AssertValueTypes(t, initializationDNSSchema, map[string]schema.ValueType{
mkInitializationDNSDomain: schema.TypeString,
mkInitializationDNSServer: schema.TypeString,
mkInitializationDNSServers: schema.TypeList,
})
initializationIPConfigSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkInitializationIPConfig,
)
test.AssertOptionalArguments(t, initializationIPConfigSchema, []string{
mkInitializationIPConfigIPv4,
mkInitializationIPConfigIPv6,
})
test.AssertValueTypes(t, initializationIPConfigSchema, map[string]schema.ValueType{
mkInitializationIPConfigIPv4: schema.TypeList,
mkInitializationIPConfigIPv6: schema.TypeList,
})
initializationIPConfigIPv4Schema := test.AssertNestedSchemaExistence(
t,
initializationIPConfigSchema,
mkInitializationIPConfigIPv4,
)
test.AssertOptionalArguments(t, initializationIPConfigIPv4Schema, []string{
mkInitializationIPConfigIPv4Address,
mkInitializationIPConfigIPv4Gateway,
})
test.AssertValueTypes(t, initializationIPConfigIPv4Schema, map[string]schema.ValueType{
mkInitializationIPConfigIPv4Address: schema.TypeString,
mkInitializationIPConfigIPv4Gateway: schema.TypeString,
})
initializationIPConfigIPv6Schema := test.AssertNestedSchemaExistence(
t,
initializationIPConfigSchema,
mkInitializationIPConfigIPv6,
)
test.AssertOptionalArguments(t, initializationIPConfigIPv6Schema, []string{
mkInitializationIPConfigIPv6Address,
mkInitializationIPConfigIPv6Gateway,
})
test.AssertValueTypes(t, initializationIPConfigIPv6Schema, map[string]schema.ValueType{
mkInitializationIPConfigIPv6Address: schema.TypeString,
mkInitializationIPConfigIPv6Gateway: schema.TypeString,
})
initializationUserAccountSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkInitializationUserAccount,
)
test.AssertOptionalArguments(t, initializationUserAccountSchema, []string{
mkInitializationUserAccountKeys,
mkInitializationUserAccountPassword,
mkInitializationUserAccountUsername,
})
test.AssertValueTypes(t, initializationUserAccountSchema, map[string]schema.ValueType{
mkInitializationUserAccountKeys: schema.TypeList,
mkInitializationUserAccountPassword: schema.TypeString,
mkInitializationUserAccountUsername: schema.TypeString,
})
memorySchema := test.AssertNestedSchemaExistence(t, s, mkMemory)
test.AssertOptionalArguments(t, memorySchema, []string{
mkMemoryDedicated,
mkMemoryFloating,
mkMemoryShared,
})
test.AssertValueTypes(t, memorySchema, map[string]schema.ValueType{
mkMemoryDedicated: schema.TypeInt,
mkMemoryFloating: schema.TypeInt,
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,
mkOperatingSystem,
)
test.AssertOptionalArguments(t, operatingSystemSchema, []string{
mkOperatingSystemType,
})
test.AssertValueTypes(t, operatingSystemSchema, map[string]schema.ValueType{
mkOperatingSystemType: schema.TypeString,
})
serialDeviceSchema := test.AssertNestedSchemaExistence(
t,
s,
mkSerialDevice,
)
test.AssertOptionalArguments(t, serialDeviceSchema, []string{
mkSerialDeviceDevice,
})
test.AssertValueTypes(t, serialDeviceSchema, map[string]schema.ValueType{
mkSerialDeviceDevice: schema.TypeString,
})
vgaSchema := test.AssertNestedSchemaExistence(t, s, mkVGA)
test.AssertOptionalArguments(t, vgaSchema, []string{
mkVGAEnabled,
mkVGAMemory,
mkVGAType,
})
test.AssertValueTypes(t, vgaSchema, map[string]schema.ValueType{
mkVGAEnabled: schema.TypeBool,
mkVGAMemory: schema.TypeInt,
mkVGAType: 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()
nodeName, id, err := parseImportIDWithNodeName(tt.value)
if !tt.valid {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedNodeName, nodeName)
require.Equal(t, tt.expectedID, id)
})
}
}

View File

@ -1,492 +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 (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/stretchr/testify/require"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
)
// TestVMInstantiation tests whether the VM instance can be instantiated.
func TestVMInstantiation(t *testing.T) {
t.Parallel()
s := VM()
if s == nil {
t.Fatalf("Cannot instantiate VM")
}
}
// TestVMSchema tests the VM schema.
func TestVMSchema(t *testing.T) {
t.Parallel()
s := VM()
test.AssertRequiredArguments(t, s, []string{
mkResourceVirtualEnvironmentVMNodeName,
})
test.AssertOptionalArguments(t, s, []string{
mkResourceVirtualEnvironmentVMACPI,
mkResourceVirtualEnvironmentVMAgent,
mkResourceVirtualEnvironmentVMAudioDevice,
mkResourceVirtualEnvironmentVMBIOS,
mkResourceVirtualEnvironmentVMBootOrder,
mkResourceVirtualEnvironmentVMCDROM,
mkResourceVirtualEnvironmentVMClone,
mkResourceVirtualEnvironmentVMCPU,
mkResourceVirtualEnvironmentVMDescription,
mkResourceVirtualEnvironmentVMDisk,
mkResourceVirtualEnvironmentVMEFIDisk,
mkResourceVirtualEnvironmentVMInitialization,
mkResourceVirtualEnvironmentVMHostPCI,
mkResourceVirtualEnvironmentVMHostUSB,
mkResourceVirtualEnvironmentVMKeyboardLayout,
mkResourceVirtualEnvironmentVMKVMArguments,
mkResourceVirtualEnvironmentVMMachine,
mkResourceVirtualEnvironmentVMMemory,
mkResourceVirtualEnvironmentVMName,
mkResourceVirtualEnvironmentVMNetworkDevice,
mkResourceVirtualEnvironmentVMOperatingSystem,
mkResourceVirtualEnvironmentVMPoolID,
mkResourceVirtualEnvironmentVMSerialDevice,
mkResourceVirtualEnvironmentVMStarted,
mkResourceVirtualEnvironmentVMTabletDevice,
mkResourceVirtualEnvironmentVMTemplate,
mkResourceVirtualEnvironmentVMVMID,
mkResourceVirtualEnvironmentVMSCSIHardware,
})
test.AssertComputedAttributes(t, s, []string{
mkResourceVirtualEnvironmentVMIPv4Addresses,
mkResourceVirtualEnvironmentVMIPv6Addresses,
mkResourceVirtualEnvironmentVMMACAddresses,
mkResourceVirtualEnvironmentVMNetworkInterfaceNames,
})
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMACPI: schema.TypeBool,
mkResourceVirtualEnvironmentVMAgent: schema.TypeList,
mkResourceVirtualEnvironmentVMAudioDevice: schema.TypeList,
mkResourceVirtualEnvironmentVMBIOS: schema.TypeString,
mkResourceVirtualEnvironmentVMBootOrder: schema.TypeList,
mkResourceVirtualEnvironmentVMCDROM: schema.TypeList,
mkResourceVirtualEnvironmentVMCPU: schema.TypeList,
mkResourceVirtualEnvironmentVMDescription: schema.TypeString,
mkResourceVirtualEnvironmentVMDisk: schema.TypeList,
mkResourceVirtualEnvironmentVMEFIDisk: schema.TypeList,
mkResourceVirtualEnvironmentVMHostPCI: schema.TypeList,
mkResourceVirtualEnvironmentVMHostUSB: schema.TypeList,
mkResourceVirtualEnvironmentVMInitialization: schema.TypeList,
mkResourceVirtualEnvironmentVMIPv4Addresses: schema.TypeList,
mkResourceVirtualEnvironmentVMIPv6Addresses: schema.TypeList,
mkResourceVirtualEnvironmentVMKeyboardLayout: schema.TypeString,
mkResourceVirtualEnvironmentVMKVMArguments: schema.TypeString,
mkResourceVirtualEnvironmentVMMachine: schema.TypeString,
mkResourceVirtualEnvironmentVMMemory: schema.TypeList,
mkResourceVirtualEnvironmentVMName: schema.TypeString,
mkResourceVirtualEnvironmentVMNetworkDevice: schema.TypeList,
mkResourceVirtualEnvironmentVMMACAddresses: schema.TypeList,
mkResourceVirtualEnvironmentVMNetworkInterfaceNames: schema.TypeList,
mkResourceVirtualEnvironmentVMOperatingSystem: schema.TypeList,
mkResourceVirtualEnvironmentVMPoolID: schema.TypeString,
mkResourceVirtualEnvironmentVMSerialDevice: schema.TypeList,
mkResourceVirtualEnvironmentVMStarted: schema.TypeBool,
mkResourceVirtualEnvironmentVMTabletDevice: schema.TypeBool,
mkResourceVirtualEnvironmentVMTemplate: schema.TypeBool,
mkResourceVirtualEnvironmentVMVMID: schema.TypeInt,
mkResourceVirtualEnvironmentVMSCSIHardware: schema.TypeString,
})
agentSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMAgent)
test.AssertOptionalArguments(t, agentSchema, []string{
mkResourceVirtualEnvironmentVMAgentEnabled,
mkResourceVirtualEnvironmentVMAgentTimeout,
mkResourceVirtualEnvironmentVMAgentTrim,
mkResourceVirtualEnvironmentVMAgentType,
})
test.AssertValueTypes(t, agentSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMAgentEnabled: schema.TypeBool,
mkResourceVirtualEnvironmentVMAgentTrim: schema.TypeBool,
mkResourceVirtualEnvironmentVMAgentType: schema.TypeString,
})
audioDeviceSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMAudioDevice)
test.AssertOptionalArguments(t, audioDeviceSchema, []string{
mkResourceVirtualEnvironmentVMAudioDeviceDevice,
mkResourceVirtualEnvironmentVMAudioDeviceDriver,
})
test.AssertValueTypes(t, audioDeviceSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMAudioDeviceDevice: schema.TypeString,
mkResourceVirtualEnvironmentVMAudioDeviceDriver: schema.TypeString,
})
cdromSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMCDROM)
test.AssertOptionalArguments(t, cdromSchema, []string{
mkResourceVirtualEnvironmentVMCDROMEnabled,
mkResourceVirtualEnvironmentVMCDROMFileID,
})
test.AssertValueTypes(t, cdromSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMCDROMEnabled: schema.TypeBool,
mkResourceVirtualEnvironmentVMCDROMFileID: schema.TypeString,
})
cloneSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMClone)
test.AssertRequiredArguments(t, cloneSchema, []string{
mkResourceVirtualEnvironmentVMCloneVMID,
})
test.AssertOptionalArguments(t, cloneSchema, []string{
mkResourceVirtualEnvironmentVMCloneDatastoreID,
mkResourceVirtualEnvironmentVMCloneNodeName,
})
test.AssertValueTypes(t, cloneSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMCloneDatastoreID: schema.TypeString,
mkResourceVirtualEnvironmentVMCloneNodeName: schema.TypeString,
mkResourceVirtualEnvironmentVMCloneVMID: schema.TypeInt,
})
cpuSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMCPU)
test.AssertOptionalArguments(t, cpuSchema, []string{
mkResourceVirtualEnvironmentVMCPUArchitecture,
mkResourceVirtualEnvironmentVMCPUCores,
mkResourceVirtualEnvironmentVMCPUFlags,
mkResourceVirtualEnvironmentVMCPUHotplugged,
mkResourceVirtualEnvironmentVMCPUNUMA,
mkResourceVirtualEnvironmentVMCPUSockets,
mkResourceVirtualEnvironmentVMCPUType,
mkResourceVirtualEnvironmentVMCPUUnits,
})
test.AssertValueTypes(t, cpuSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMCPUArchitecture: schema.TypeString,
mkResourceVirtualEnvironmentVMCPUCores: schema.TypeInt,
mkResourceVirtualEnvironmentVMCPUFlags: schema.TypeList,
mkResourceVirtualEnvironmentVMCPUHotplugged: schema.TypeInt,
mkResourceVirtualEnvironmentVMCPUNUMA: schema.TypeBool,
mkResourceVirtualEnvironmentVMCPUSockets: schema.TypeInt,
mkResourceVirtualEnvironmentVMCPUType: schema.TypeString,
mkResourceVirtualEnvironmentVMCPUUnits: schema.TypeInt,
})
diskSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMDisk)
test.AssertOptionalArguments(t, diskSchema, []string{
mkResourceVirtualEnvironmentVMDiskDatastoreID,
mkResourceVirtualEnvironmentVMDiskPathInDatastore,
mkResourceVirtualEnvironmentVMDiskFileFormat,
mkResourceVirtualEnvironmentVMDiskFileID,
mkResourceVirtualEnvironmentVMDiskSize,
})
test.AssertValueTypes(t, diskSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMDiskDatastoreID: schema.TypeString,
mkResourceVirtualEnvironmentVMDiskPathInDatastore: schema.TypeString,
mkResourceVirtualEnvironmentVMDiskFileFormat: schema.TypeString,
mkResourceVirtualEnvironmentVMDiskFileID: schema.TypeString,
mkResourceVirtualEnvironmentVMDiskSize: schema.TypeInt,
})
diskSpeedSchema := test.AssertNestedSchemaExistence(
t,
diskSchema,
mkResourceVirtualEnvironmentVMDiskSpeed,
)
test.AssertOptionalArguments(t, diskSpeedSchema, []string{
mkResourceVirtualEnvironmentVMDiskSpeedRead,
mkResourceVirtualEnvironmentVMDiskSpeedReadBurstable,
mkResourceVirtualEnvironmentVMDiskSpeedWrite,
mkResourceVirtualEnvironmentVMDiskSpeedWriteBurstable,
})
test.AssertValueTypes(t, diskSpeedSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMDiskSpeedRead: schema.TypeInt,
mkResourceVirtualEnvironmentVMDiskSpeedReadBurstable: schema.TypeInt,
mkResourceVirtualEnvironmentVMDiskSpeedWrite: schema.TypeInt,
mkResourceVirtualEnvironmentVMDiskSpeedWriteBurstable: schema.TypeInt,
})
efiDiskSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMEFIDisk)
test.AssertOptionalArguments(t, efiDiskSchema, []string{
mkResourceVirtualEnvironmentVMEFIDiskDatastoreID,
mkResourceVirtualEnvironmentVMEFIDiskFileFormat,
mkResourceVirtualEnvironmentVMEFIDiskType,
})
test.AssertValueTypes(t, efiDiskSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMEFIDiskDatastoreID: schema.TypeString,
mkResourceVirtualEnvironmentVMEFIDiskFileFormat: schema.TypeString,
mkResourceVirtualEnvironmentVMEFIDiskType: schema.TypeString,
})
initializationSchema := test.AssertNestedSchemaExistence(
t,
s,
mkResourceVirtualEnvironmentVMInitialization,
)
test.AssertOptionalArguments(t, initializationSchema, []string{
mkResourceVirtualEnvironmentVMInitializationDatastoreID,
mkResourceVirtualEnvironmentVMInitializationInterface,
mkResourceVirtualEnvironmentVMInitializationDNS,
mkResourceVirtualEnvironmentVMInitializationIPConfig,
mkResourceVirtualEnvironmentVMInitializationUserAccount,
})
test.AssertValueTypes(t, initializationSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationDatastoreID: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationInterface: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationDNS: schema.TypeList,
mkResourceVirtualEnvironmentVMInitializationIPConfig: schema.TypeList,
mkResourceVirtualEnvironmentVMInitializationUserAccount: schema.TypeList,
})
hostPCISchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMHostPCI)
test.AssertOptionalArguments(t, hostPCISchema, []string{
mkResourceVirtualEnvironmentVMHostPCIDeviceMDev,
mkResourceVirtualEnvironmentVMHostPCIDevicePCIE,
mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR,
mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile,
mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA,
})
test.AssertValueTypes(t, hostPCISchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMHostPCIDevice: schema.TypeString,
mkResourceVirtualEnvironmentVMHostPCIDeviceMDev: schema.TypeString,
mkResourceVirtualEnvironmentVMHostPCIDevicePCIE: schema.TypeBool,
mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR: schema.TypeBool,
mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile: schema.TypeString,
mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA: schema.TypeBool,
})
hostUSBSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMHostUSB)
test.AssertOptionalArguments(t, hostUSBSchema, []string{
mkResourceVirtualEnvironmentVMHostUSBDeviceMapping,
})
test.AssertValueTypes(t, hostUSBSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMHostUSBDevice: schema.TypeString,
mkResourceVirtualEnvironmentVMHostUSBDeviceUSB3: schema.TypeBool,
})
initializationDNSSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkResourceVirtualEnvironmentVMInitializationDNS,
)
test.AssertOptionalArguments(t, initializationDNSSchema, []string{
mkResourceVirtualEnvironmentVMInitializationDNSDomain,
mkResourceVirtualEnvironmentVMInitializationDNSServer,
mkResourceVirtualEnvironmentVMInitializationDNSServers,
})
test.AssertValueTypes(t, initializationDNSSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationDNSDomain: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationDNSServer: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationDNSServers: schema.TypeList,
})
initializationIPConfigSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkResourceVirtualEnvironmentVMInitializationIPConfig,
)
test.AssertOptionalArguments(t, initializationIPConfigSchema, []string{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6,
})
test.AssertValueTypes(t, initializationIPConfigSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4: schema.TypeList,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6: schema.TypeList,
})
initializationIPConfigIPv4Schema := test.AssertNestedSchemaExistence(
t,
initializationIPConfigSchema,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4,
)
test.AssertOptionalArguments(t, initializationIPConfigIPv4Schema, []string{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4Address,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4Gateway,
})
test.AssertValueTypes(t, initializationIPConfigIPv4Schema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4Address: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv4Gateway: schema.TypeString,
})
initializationIPConfigIPv6Schema := test.AssertNestedSchemaExistence(
t,
initializationIPConfigSchema,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6,
)
test.AssertOptionalArguments(t, initializationIPConfigIPv6Schema, []string{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6Address,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6Gateway,
})
test.AssertValueTypes(t, initializationIPConfigIPv6Schema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6Address: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationIPConfigIPv6Gateway: schema.TypeString,
})
initializationUserAccountSchema := test.AssertNestedSchemaExistence(
t,
initializationSchema,
mkResourceVirtualEnvironmentVMInitializationUserAccount,
)
test.AssertOptionalArguments(t, initializationUserAccountSchema, []string{
mkResourceVirtualEnvironmentVMInitializationUserAccountKeys,
mkResourceVirtualEnvironmentVMInitializationUserAccountPassword,
mkResourceVirtualEnvironmentVMInitializationUserAccountUsername,
})
test.AssertValueTypes(t, initializationUserAccountSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMInitializationUserAccountKeys: schema.TypeList,
mkResourceVirtualEnvironmentVMInitializationUserAccountPassword: schema.TypeString,
mkResourceVirtualEnvironmentVMInitializationUserAccountUsername: schema.TypeString,
})
memorySchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMMemory)
test.AssertOptionalArguments(t, memorySchema, []string{
mkResourceVirtualEnvironmentVMMemoryDedicated,
mkResourceVirtualEnvironmentVMMemoryFloating,
mkResourceVirtualEnvironmentVMMemoryShared,
})
test.AssertValueTypes(t, memorySchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMMemoryDedicated: schema.TypeInt,
mkResourceVirtualEnvironmentVMMemoryFloating: schema.TypeInt,
mkResourceVirtualEnvironmentVMMemoryShared: schema.TypeInt,
})
networkDeviceSchema := test.AssertNestedSchemaExistence(
t,
s,
mkResourceVirtualEnvironmentVMNetworkDevice,
)
test.AssertOptionalArguments(t, networkDeviceSchema, []string{
mkResourceVirtualEnvironmentVMNetworkDeviceBridge,
mkResourceVirtualEnvironmentVMNetworkDeviceEnabled,
mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress,
mkResourceVirtualEnvironmentVMNetworkDeviceModel,
mkResourceVirtualEnvironmentVMNetworkDeviceRateLimit,
mkResourceVirtualEnvironmentVMNetworkDeviceVLANID,
mkResourceVirtualEnvironmentVMNetworkDeviceMTU,
})
test.AssertValueTypes(t, networkDeviceSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMNetworkDeviceBridge: schema.TypeString,
mkResourceVirtualEnvironmentVMNetworkDeviceEnabled: schema.TypeBool,
mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress: schema.TypeString,
mkResourceVirtualEnvironmentVMNetworkDeviceModel: schema.TypeString,
mkResourceVirtualEnvironmentVMNetworkDeviceRateLimit: schema.TypeFloat,
mkResourceVirtualEnvironmentVMNetworkDeviceVLANID: schema.TypeInt,
mkResourceVirtualEnvironmentVMNetworkDeviceMTU: schema.TypeInt,
})
operatingSystemSchema := test.AssertNestedSchemaExistence(
t,
s,
mkResourceVirtualEnvironmentVMOperatingSystem,
)
test.AssertOptionalArguments(t, operatingSystemSchema, []string{
mkResourceVirtualEnvironmentVMOperatingSystemType,
})
test.AssertValueTypes(t, operatingSystemSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMOperatingSystemType: schema.TypeString,
})
serialDeviceSchema := test.AssertNestedSchemaExistence(
t,
s,
mkResourceVirtualEnvironmentVMSerialDevice,
)
test.AssertOptionalArguments(t, serialDeviceSchema, []string{
mkResourceVirtualEnvironmentVMSerialDeviceDevice,
})
test.AssertValueTypes(t, serialDeviceSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMSerialDeviceDevice: schema.TypeString,
})
vgaSchema := test.AssertNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMVGA)
test.AssertOptionalArguments(t, vgaSchema, []string{
mkResourceVirtualEnvironmentVMVGAEnabled,
mkResourceVirtualEnvironmentVMVGAMemory,
mkResourceVirtualEnvironmentVMVGAType,
})
test.AssertValueTypes(t, vgaSchema, map[string]schema.ValueType{
mkResourceVirtualEnvironmentVMVGAEnabled: schema.TypeBool,
mkResourceVirtualEnvironmentVMVGAMemory: schema.TypeInt,
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()
nodeName, id, err := parseImportIDWithNodeName(tt.value)
if !tt.valid {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedNodeName, nodeName)
require.Equal(t, tt.expectedID, id)
})
}
}