mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-08-22 11:28:33 +00:00
Continued work on VM resource
This commit is contained in:
parent
96d139fcb4
commit
c69cabc57a
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@
|
||||
/website/node_modules
|
||||
/website/vendor
|
||||
|
||||
autogenerated/
|
||||
bin/
|
||||
dist/
|
||||
modules-dev/
|
||||
|
@ -3,7 +3,6 @@ resource "proxmox_virtual_environment_file" "ubuntu_cloud_image" {
|
||||
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local"))}"
|
||||
node_name = "${data.proxmox_virtual_environment_datastores.example.node_name}"
|
||||
source = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img"
|
||||
source_checksum = "6afb97af96b671572389935d6579557357ad7bbf2c2dd2cb52879c957c85dbee"
|
||||
}
|
||||
|
||||
output "resource_proxmox_virtual_environment_file_ubuntu_cloud_image_content_type" {
|
||||
|
@ -16,9 +16,25 @@ resource "proxmox_virtual_environment_vm" "example" {
|
||||
}
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local-lvm"))}"
|
||||
file_id = "${proxmox_virtual_environment_file.ubuntu_cloud_image.id}"
|
||||
}
|
||||
|
||||
network_device {}
|
||||
|
||||
node_name = "${data.proxmox_virtual_environment_nodes.example.names[0]}"
|
||||
os_type = "l26"
|
||||
}
|
||||
|
||||
resource "local_file" "example_ssh_private_key" {
|
||||
filename = "${path.module}/autogenerated/id_rsa"
|
||||
sensitive_content = "${tls_private_key.example.private_key_pem}"
|
||||
}
|
||||
|
||||
resource "local_file" "example_ssh_public_key" {
|
||||
filename = "${path.module}/autogenerated/id_rsa.pub"
|
||||
sensitive_content = "${tls_private_key.example.public_key_openssh}"
|
||||
}
|
||||
|
||||
resource "tls_private_key" "example" {
|
||||
|
1
go.mod
1
go.mod
@ -5,4 +5,5 @@ go 1.13
|
||||
require (
|
||||
github.com/google/go-querystring v1.0.0
|
||||
github.com/hashicorp/terraform v0.12.18
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
)
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -150,6 +151,9 @@ func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody in
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to decode HTTP %s response (path: %s) - Reason: %s", method, modifiedPath, err.Error())
|
||||
}
|
||||
} else {
|
||||
data, _ := ioutil.ReadAll(res.Body)
|
||||
log.Printf("[DEBUG] Unhandled HTTP response body: %s", string(data))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -6,9 +6,96 @@ package proxmox
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// ExecuteNodeCommands executes commands on a given node.
|
||||
func (c *VirtualEnvironmentClient) ExecuteNodeCommands(nodeName string, commands []string) error {
|
||||
// We must first retrieve the IP address of the node as we need to bypass the API and use SSH instead.
|
||||
networkDevices, err := c.ListNodeNetworkDevices(nodeName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeAddress := ""
|
||||
|
||||
for _, d := range networkDevices {
|
||||
if d.Address != nil {
|
||||
nodeAddress = *d.Address
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if nodeAddress == "" {
|
||||
return fmt.Errorf("Failed to determine the IP address of node \"%s\"", nodeName)
|
||||
}
|
||||
|
||||
// We can now go ahead and execute the commands using SSH.
|
||||
// Hopefully, the developers will add this feature to the REST API at some point.
|
||||
ur := strings.Split(c.Username, "@")
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: ur[0],
|
||||
Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
sshClient, err := ssh.Dial("tcp", nodeAddress+":22", sshConfig)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer sshClient.Close()
|
||||
|
||||
sshSession, err := sshClient.NewSession()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer sshSession.Close()
|
||||
|
||||
_, err = sshSession.CombinedOutput(
|
||||
fmt.Sprintf(
|
||||
"/bin/bash -c '%s'",
|
||||
strings.ReplaceAll(strings.Join(commands, " && "), "'", "'\"'\"'"),
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListNodeNetworkDevices retrieves a list of network devices for a specific nodes.
|
||||
func (c *VirtualEnvironmentClient) ListNodeNetworkDevices(nodeName string) ([]*VirtualEnvironmentNodeNetworkDeviceListResponseData, error) {
|
||||
resBody := &VirtualEnvironmentNodeNetworkDeviceListResponseBody{}
|
||||
err := c.DoRequest(hmGET, fmt.Sprintf("nodes/%s/network", url.PathEscape(nodeName)), nil, resBody)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return nil, errors.New("The server did not include a data object in the response")
|
||||
}
|
||||
|
||||
sort.Slice(resBody.Data, func(i, j int) bool {
|
||||
return resBody.Data[i].Priority < resBody.Data[j].Priority
|
||||
})
|
||||
|
||||
return resBody.Data, nil
|
||||
}
|
||||
|
||||
// ListNodes retrieves a list of nodes.
|
||||
func (c *VirtualEnvironmentClient) ListNodes() ([]*VirtualEnvironmentNodeListResponseData, error) {
|
||||
resBody := &VirtualEnvironmentNodeListResponseBody{}
|
||||
|
@ -4,6 +4,19 @@
|
||||
|
||||
package proxmox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// CustomNodeCommands contains an array of commands to execute.
|
||||
type CustomNodeCommands []string
|
||||
|
||||
// VirtualEnvironmentNodeExecuteRequestBody contains the data for a node execute request.
|
||||
type VirtualEnvironmentNodeExecuteRequestBody struct {
|
||||
Commands CustomNodeCommands `json:"commands" url:"commands"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentNodeListResponseBody contains the body from a node list response.
|
||||
type VirtualEnvironmentNodeListResponseBody struct {
|
||||
Data []*VirtualEnvironmentNodeListResponseData `json:"data,omitempty"`
|
||||
@ -21,3 +34,41 @@ type VirtualEnvironmentNodeListResponseData struct {
|
||||
SupportLevel *string `json:"level,omitempty"`
|
||||
Uptime *int `json:"uptime"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentNodeNetworkDeviceListResponseBody contains the body from a node network device list response.
|
||||
type VirtualEnvironmentNodeNetworkDeviceListResponseBody struct {
|
||||
Data []*VirtualEnvironmentNodeNetworkDeviceListResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentNodeNetworkDeviceListResponseData contains the data from a node network device list response.
|
||||
type VirtualEnvironmentNodeNetworkDeviceListResponseData struct {
|
||||
Active *CustomBool `json:"active,omitempty"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
Autostart *CustomBool `json:"autostart,omitempty"`
|
||||
BridgeFD *string `json:"bridge_fd,omitempty"`
|
||||
BridgePorts *string `json:"bridge_ports,omitempty"`
|
||||
BridgeSTP *string `json:"bridge_stp,omitempty"`
|
||||
CIDR *string `json:"cidr,omitempty"`
|
||||
Exists *CustomBool `json:"exists,omitempty"`
|
||||
Families *[]string `json:"families,omitempty"`
|
||||
Gateway *string `json:"gateway,omitempty"`
|
||||
Iface string `json:"iface"`
|
||||
MethodIPv4 *string `json:"method,omitempty"`
|
||||
MethodIPv6 *string `json:"method6,omitempty"`
|
||||
Netmask *string `json:"netmask,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomNodeCommands array to a JSON encoded URL vlaue.
|
||||
func (r CustomNodeCommands) EncodeValues(key string, v *url.Values) error {
|
||||
jsonArrayBytes, err := json.Marshal(r)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Add(key, string(jsonArrayBytes))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ type VirtualEnvironmentVMCreateRequestBody struct {
|
||||
PCIDevices CustomPCIDevices `json:"hostpci,omitempty" url:"hostpci,omitempty"`
|
||||
Revert *string `json:"revert,omitempty" url:"revert,omitempty"`
|
||||
SATADevices CustomStorageDevices `json:"sata,omitempty" url:"sata,omitempty"`
|
||||
SCSIDevices CustomStorageDevices `json:"scsi,omitempty" url:"sata,omitempty"`
|
||||
SCSIDevices CustomStorageDevices `json:"scsi,omitempty" url:"scsi,omitempty"`
|
||||
SCSIHardware *string `json:"scsihw,omitempty" url:"scsihw,omitempty"`
|
||||
SerialDevices CustomSerialDevices `json:"serial,omitempty" url:"serial,omitempty"`
|
||||
SharedMemory *CustomSharedMemory `json:"ivshmem,omitempty" url:"ivshmem,omitempty"`
|
||||
|
@ -6,6 +6,7 @@ package proxmoxtf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -610,6 +611,30 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
cpuCores := cpuBlock[mkResourceVirtualEnvironmentVMCPUCores].(int)
|
||||
cpuSockets := cpuBlock[mkResourceVirtualEnvironmentVMCPUSockets].(int)
|
||||
|
||||
disk := d.Get(mkResourceVirtualEnvironmentVMDisk).([]interface{})
|
||||
scsiDevices := make(proxmox.CustomStorageDevices, len(disk))
|
||||
|
||||
for i, d := range disk {
|
||||
block := d.(map[string]interface{})
|
||||
|
||||
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
|
||||
enabled, _ := block[mkResourceVirtualEnvironmentVMDiskEnabled].(bool)
|
||||
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
|
||||
|
||||
diskDevice := proxmox.CustomStorageDevice{
|
||||
Enabled: enabled,
|
||||
}
|
||||
|
||||
if fileID != "" {
|
||||
diskDevice.Enabled = false
|
||||
} else {
|
||||
diskDevice.FileVolume = fmt.Sprintf("%s:%d", datastoreID, size)
|
||||
}
|
||||
|
||||
scsiDevices[i] = diskDevice
|
||||
}
|
||||
|
||||
keyboardLayout := d.Get(mkResourceVirtualEnvironmentVMKeyboardLayout).(string)
|
||||
memory := d.Get(mkResourceVirtualEnvironmentVMMemory).([]interface{})
|
||||
|
||||
@ -679,6 +704,7 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
var memorySharedObject *proxmox.CustomSharedMemory
|
||||
|
||||
agentEnabled := proxmox.CustomBool(true)
|
||||
bootDisk := "scsi0"
|
||||
bootOrder := "c"
|
||||
|
||||
if cdromEnabled {
|
||||
@ -713,6 +739,7 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
|
||||
body := &proxmox.VirtualEnvironmentVMCreateRequestBody{
|
||||
Agent: &proxmox.CustomAgent{Enabled: &agentEnabled},
|
||||
BootDisk: &bootDisk,
|
||||
BootOrder: &bootOrder,
|
||||
CloudInitConfig: cloudInitConfig,
|
||||
CPUCores: &cpuCores,
|
||||
@ -723,11 +750,11 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
KeyboardLayout: &keyboardLayout,
|
||||
NetworkDevices: networkDeviceObjects,
|
||||
OSType: &osType,
|
||||
SCSIDevices: scsiDevices,
|
||||
SCSIHardware: &scsiHardware,
|
||||
SerialDevices: []string{"socket"},
|
||||
SharedMemory: memorySharedObject,
|
||||
TabletDeviceEnabled: &tabletDeviceEnabled,
|
||||
VGADevice: &proxmox.CustomVGADevice{Type: "serial0"},
|
||||
VMID: &vmID,
|
||||
}
|
||||
|
||||
@ -743,6 +770,85 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
|
||||
d.SetId(strconv.Itoa(vmID))
|
||||
|
||||
return resourceVirtualEnvironmentVMImportDisks(d, m)
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentVMImportDisks(d *schema.ResourceData, m interface{}) error {
|
||||
config := m.(providerConfiguration)
|
||||
veClient, err := config.GetVEClient()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
|
||||
vmID, err := strconv.Atoi(d.Id())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commands := []string{}
|
||||
|
||||
// Determine the ID of the next disk.
|
||||
disk := d.Get(mkResourceVirtualEnvironmentVMDisk).([]interface{})
|
||||
diskCount := 0
|
||||
|
||||
for _, d := range disk {
|
||||
block := d.(map[string]interface{})
|
||||
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
|
||||
if fileID == "" {
|
||||
diskCount++
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the commands required to import the specified disks.
|
||||
importedDiskCount := 0
|
||||
|
||||
for i, d := range disk {
|
||||
block := d.(map[string]interface{})
|
||||
|
||||
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
|
||||
enabled, _ := block[mkResourceVirtualEnvironmentVMDiskEnabled].(bool)
|
||||
fileFormat, _ := block[mkResourceVirtualEnvironmentVMDiskFileFormat].(string)
|
||||
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
|
||||
|
||||
if !enabled || fileID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fileIDParts := strings.Split(fileID, ":")
|
||||
filePath := fmt.Sprintf("/var/lib/vz/template/%s", fileIDParts[1])
|
||||
filePathTmp := fmt.Sprintf("/tmp/vm-%d-disk-%d.%s", vmID, diskCount+importedDiskCount, fileFormat)
|
||||
|
||||
commands = append(
|
||||
commands,
|
||||
fmt.Sprintf("cp %s %s", filePath, filePathTmp),
|
||||
fmt.Sprintf("qemu-img resize %s %dG", filePathTmp, size),
|
||||
fmt.Sprintf("qm importdisk %d %s %s -format qcow2", vmID, filePathTmp, datastoreID),
|
||||
fmt.Sprintf("qm set %d --scsi%d %s:vm-%d-disk-%d", vmID, i, datastoreID, vmID, diskCount+importedDiskCount),
|
||||
fmt.Sprintf("rm -f %s", filePathTmp),
|
||||
)
|
||||
|
||||
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 {
|
||||
for _, cmd := range commands {
|
||||
log.Printf("[DEBUG] Node command: %s", cmd)
|
||||
}
|
||||
|
||||
err = veClient.ExecuteNodeCommands(nodeName, commands)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return resourceVirtualEnvironmentVMRead(d, m)
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
|
||||
testOptionalArguments(t, s, []string{
|
||||
mkResourceVirtualEnvironmentVMCDROM,
|
||||
mkResourceVirtualEnvironmentVMCloudInit,
|
||||
mkResourceVirtualEnvironmentVMCPU,
|
||||
mkResourceVirtualEnvironmentVMDisk,
|
||||
mkResourceVirtualEnvironmentVMKeyboardLayout,
|
||||
@ -41,6 +42,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
|
||||
testSchemaValueTypes(t, s, []string{
|
||||
mkResourceVirtualEnvironmentVMCDROM,
|
||||
mkResourceVirtualEnvironmentVMCloudInit,
|
||||
mkResourceVirtualEnvironmentVMCPU,
|
||||
mkResourceVirtualEnvironmentVMDisk,
|
||||
mkResourceVirtualEnvironmentVMKeyboardLayout,
|
||||
@ -53,6 +55,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
@ -76,6 +79,102 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
schema.TypeString,
|
||||
})
|
||||
|
||||
cloudInitSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMCloudInit)
|
||||
|
||||
testRequiredArguments(t, cloudInitSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccount,
|
||||
})
|
||||
|
||||
testOptionalArguments(t, cloudInitSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNS,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfig,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNS,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfig,
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccount,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
})
|
||||
|
||||
cloudInitDNSSchema := testNestedSchemaExistence(t, cloudInitSchema, mkResourceVirtualEnvironmentVMCloudInitDNS)
|
||||
|
||||
testOptionalArguments(t, cloudInitDNSSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNSDomain,
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNSServer,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitDNSSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNSDomain,
|
||||
mkResourceVirtualEnvironmentVMCloudInitDNSServer,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
})
|
||||
|
||||
cloudInitIPConfigSchema := testNestedSchemaExistence(t, cloudInitSchema, mkResourceVirtualEnvironmentVMCloudInitIPConfig)
|
||||
|
||||
testOptionalArguments(t, cloudInitIPConfigSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitIPConfigSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
})
|
||||
|
||||
cloudInitIPConfigIPv4Schema := testNestedSchemaExistence(t, cloudInitIPConfigSchema, mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4)
|
||||
|
||||
testOptionalArguments(t, cloudInitIPConfigIPv4Schema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Address,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Gateway,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitIPConfigIPv4Schema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Address,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Gateway,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
})
|
||||
|
||||
cloudInitIPConfigIPv6Schema := testNestedSchemaExistence(t, cloudInitIPConfigSchema, mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6)
|
||||
|
||||
testOptionalArguments(t, cloudInitIPConfigIPv6Schema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Address,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Gateway,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitIPConfigIPv6Schema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Address,
|
||||
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Gateway,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
})
|
||||
|
||||
cloudInitUserAccountSchema := testNestedSchemaExistence(t, cloudInitSchema, mkResourceVirtualEnvironmentVMCloudInitUserAccount)
|
||||
|
||||
testRequiredArguments(t, cloudInitUserAccountSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccountKeys,
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccountUsername,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, cloudInitUserAccountSchema, []string{
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccountKeys,
|
||||
mkResourceVirtualEnvironmentVMCloudInitUserAccountUsername,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
})
|
||||
|
||||
cpuSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMCPU)
|
||||
|
||||
testOptionalArguments(t, cpuSchema, []string{
|
||||
|
Loading…
Reference in New Issue
Block a user