opentofu/builtin/providers/vsphere/resource_vsphere_virtual_machine_test.go
Dan Allegood 4b9b42dbf0 Fixes the hasBootableVmdk flag when attaching multiple disks (#7804)
The hasBootableFlag logic had a bug where it would only be set properly
if the bootable disk was the last specified.  Adding some bool logic
resolves the issue.  Also adding check to ensure only one bootable disk
is given, and cleaning up a redundant var.
2016-07-27 00:25:56 +01:00

1258 lines
36 KiB
Go

package vsphere
import (
"fmt"
"log"
"os"
"regexp"
"testing"
"path/filepath"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
///////
// Various ENV vars are used to setup these tests. Look for `os.Getenv`
///////
// Base setup function to check that a template, and nic information is set
// TODO needs some TLC - determine exactly how we want to do this
func testBasicPreCheck(t *testing.T) {
testAccPreCheck(t)
if v := os.Getenv("VSPHERE_TEMPLATE"); v == "" {
t.Fatal("env variable VSPHERE_TEMPLATE must be set for acceptance tests")
}
if v := os.Getenv("VSPHERE_IPV4_GATEWAY"); v == "" {
t.Fatal("env variable VSPHERE_IPV4_GATEWAY must be set for acceptance tests")
}
if v := os.Getenv("VSPHERE_IPV4_ADDRESS"); v == "" {
t.Fatal("env variable VSPHERE_IPV4_ADDRESS must be set for acceptance tests")
}
if v := os.Getenv("VSPHERE_NETWORK_LABEL"); v == "" {
t.Fatal("env variable VSPHERE_NETWORK_LABEL must be set for acceptance tests")
}
}
////
// Collects optional env vars used in the tests
////
func setupBaseVars() (string, string) {
var locationOpt string
var datastoreOpt string
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
locationOpt += fmt.Sprintf(" datacenter = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_CLUSTER"); v != "" {
locationOpt += fmt.Sprintf(" cluster = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_RESOURCE_POOL"); v != "" {
locationOpt += fmt.Sprintf(" resource_pool = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
datastoreOpt = fmt.Sprintf(" datastore = \"%s\"\n", v)
}
return locationOpt, datastoreOpt
}
////
// Structs and funcs used with DHCP data template
////
type TestDHCPBodyData struct {
template string
locationOpt string
datastoreOpt string
label string
}
func (body TestDHCPBodyData) parseDHCPTemplateConfigWithTemplate(template string) string {
return fmt.Sprintf(
template,
body.locationOpt,
body.label,
body.datastoreOpt,
body.template,
)
}
const testAccCheckVSphereTemplate_dhcp = `
%s
vcpu = 2
memory = 1024
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
// replaces data in the above template
func (body TestDHCPBodyData) parseDHCPTemplateConfig() string {
return fmt.Sprintf(
testAccCheckVSphereTemplate_dhcp,
body.locationOpt,
body.label,
body.datastoreOpt,
body.template,
)
}
func (body TestDHCPBodyData) testSprintfDHCPTemplateBodySecondArgDynamic(template string, arg string) string {
return fmt.Sprintf(
template,
body.locationOpt,
arg,
body.label,
body.datastoreOpt,
body.template,
)
}
// returns variables that are used in DHCP tests
func setupTemplateFuncDHCPData() TestDHCPBodyData {
locationOpt, datastoreOpt := setupBaseVars()
data := TestDHCPBodyData{
template: os.Getenv("VSPHERE_TEMPLATE"),
label: os.Getenv("VSPHERE_NETWORK_LABEL_DHCP"),
locationOpt: locationOpt,
datastoreOpt: datastoreOpt,
}
// log.Printf("[DEBUG] basic vars= %v", data)
return data
}
////
// Structs and funcs used with static ip data templates
////
type TemplateBasicBodyVars struct {
locationOpt string
label string
ipv4IpAddress string
ipv4Prefix string
ipv4Gateway string
datastoreOpt string
template string
}
// Takes a base template that has seven "%s" values in it, used by most fixed ip
// tests
func (body TemplateBasicBodyVars) testSprintfTemplateBody(template string) string {
return fmt.Sprintf(
template,
body.locationOpt,
body.label,
body.ipv4IpAddress,
body.ipv4Prefix,
body.ipv4Gateway,
body.datastoreOpt,
body.template,
)
}
// setups variables used by fixed ip tests
func setupTemplateBasicBodyVars() TemplateBasicBodyVars {
locationOpt, datastoreOpt := setupBaseVars()
prefix := os.Getenv("VSPHERE_IPV4_PREFIX")
if prefix == "" {
prefix = "24"
}
data := TemplateBasicBodyVars{
template: os.Getenv("VSPHERE_TEMPLATE"),
ipv4Gateway: os.Getenv("VSPHERE_IPV4_GATEWAY"),
label: os.Getenv("VSPHERE_NETWORK_LABEL"),
ipv4IpAddress: os.Getenv("VSPHERE_IPV4_ADDRESS"),
ipv4Prefix: prefix,
locationOpt: locationOpt,
datastoreOpt: datastoreOpt,
}
// log.Printf("[DEBUG] basic vars= %v", data)
return data
}
////
// Basic data to create series of testing functions
////
type TestFuncData struct {
vm virtualMachine
label string
vmName string
vmResource string
numDisks string
numCPU string
mem string
}
// returns TestCheckFunc's that are used in many of our tests
// mem defaults to 1024
// cpu defaults to 2
// disks defatuls to 1
// vmResource defaults to "terraform-test"
// vmName defaults to "vsphere_virtual_machine.foo
func (test TestFuncData) testCheckFuncBasic() (
resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc,
resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc) {
// log.Printf("[DEBUG] data= %v", test)
mem := test.mem
if mem == "" {
mem = "1024"
}
cpu := test.numCPU
if cpu == "" {
cpu = "2"
}
disks := test.numDisks
if disks == "" {
disks = "1"
}
res := test.vmResource
if res == "" {
res = "terraform-test"
}
vmName := test.vmName
if vmName == "" {
vmName = "vsphere_virtual_machine.foo"
}
return testAccCheckVSphereVirtualMachineExists(vmName, &test.vm),
resource.TestCheckResourceAttr(vmName, "name", res),
resource.TestCheckResourceAttr(vmName, "vcpu", cpu),
resource.TestMatchResourceAttr(vmName, "uuid", regexp.MustCompile("[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}")),
resource.TestCheckResourceAttr(vmName, "memory", mem),
resource.TestCheckResourceAttr(vmName, "disk.#", disks),
resource.TestCheckResourceAttr(vmName, "network_interface.#", "1"),
resource.TestCheckResourceAttr(vmName, "network_interface.0.label", test.label)
}
const testAccCheckVSphereVirtualMachineConfig_really_basic = `
resource "vsphere_virtual_machine" "foo" {
name = "terraform-test"
` + testAccTemplateBasicBodyWithEnd
// WARNING this is one of the base templates. You change this and you will
// be impacting multiple tests
const testAccTemplateBasicBody = `
%s
vcpu = 2
memory = 1024
network_interface {
label = "%s"
ipv4_address = "%s"
ipv4_prefix_length = %s
ipv4_gateway = "%s"
}
disk {
%s
template = "%s"
iops = 500
}
`
const testAccTemplateBasicBodyWithEnd = testAccTemplateBasicBody + `
}`
func TestAccVSphereVirtualMachine_basic(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testBasicPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: basic_vars.label}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_debug = `
provider "vsphere" {
client_debug = true
}
` + testAccCheckVSphereVirtualMachineConfig_really_basic
func TestAccVSphereVirtualMachine_client_debug(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_debug)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_debug)
log.Printf("[DEBUG] template config= %s", config)
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: basic_vars.label}.testCheckFuncBasic()
resource.Test(t, resource.TestCase{
PreCheck: func() { testBasicPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
testAccCheckDebugExists(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_initType = `
resource "vsphere_virtual_machine" "thin" {
name = "terraform-test"
` + testAccTemplateBasicBody + `
disk {
size = 1
iops = 500
controller_type = "scsi"
name = "one"
}
disk {
size = 1
controller_type = "ide"
type = "eager_zeroed"
name = "two"
}
}
`
func TestAccVSphereVirtualMachine_diskInitType(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_initType)
vmName := "vsphere_virtual_machine.thin"
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "3"}.testCheckFuncBasic()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_initType)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
// FIXME dynmically calculate the hashes
resource.TestCheckResourceAttr(vmName, "disk.294918912.type", "eager_zeroed"),
resource.TestCheckResourceAttr(vmName, "disk.294918912.controller_type", "ide"),
resource.TestCheckResourceAttr(vmName, "disk.1380467090.controller_type", "scsi"),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_dhcp = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
`
func TestAccVSphereVirtualMachine_dhcp(t *testing.T) {
var vm virtualMachine
data := setupTemplateFuncDHCPData()
config := testAccCheckVSphereVirtualMachineConfig_dhcp + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_dhcp+testAccCheckVSphereTemplate_dhcp)
log.Printf("[DEBUG] config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_custom_configs = `
resource "vsphere_virtual_machine" "car" {
name = "terraform-test-custom"
custom_configuration_parameters {
"foo" = "bar"
"car" = "ferrari"
"num" = 42
}
enable_disk_uuid = true
`
func TestAccVSphereVirtualMachine_custom_configs(t *testing.T) {
var vm virtualMachine
data := setupTemplateFuncDHCPData()
config := testAccCheckVSphereVirtualMachineConfig_custom_configs + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
vmName := "vsphere_virtual_machine.car"
res := "terraform-test-custom"
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: res}.testCheckFuncBasic()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_custom_configs+testAccCheckVSphereTemplate_dhcp)
log.Printf("[DEBUG] config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
testAccCheckVSphereVirtualMachineExistsHasCustomConfig(vmName, &vm),
resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.foo", "bar"),
resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.car", "ferrari"),
resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.num", "42"),
resource.TestCheckResourceAttr(vmName, "enable_disk_uuid", "true"),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_createInFolder = `
resource "vsphere_virtual_machine" "folder" {
name = "terraform-test-folder"
folder = "%s"
`
func TestAccVSphereVirtualMachine_createInExistingFolder(t *testing.T) {
var vm virtualMachine
datacenter := os.Getenv("VSPHERE_DATACENTER")
folder := "tf_test_cpureateInExistingFolder"
data := setupTemplateFuncDHCPData()
config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createInFolder,
folder,
) + data.parseDHCPTemplateConfig()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createInFolder)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineDestroy,
removeVSphereFolder(datacenter, folder, ""),
),
Steps: []resource.TestStep{
resource.TestStep{
PreConfig: func() { createVSphereFolder(datacenter, folder) },
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.folder", vmResource: "terraform-test-folder"}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_createWithFolder = `
resource "vsphere_folder" "with_folder" {
path = "%s"
%s
}
resource "vsphere_virtual_machine" "with_folder" {
name = "terraform-test-with-folder"
folder = "${vsphere_folder.with_folder.path}"
`
func TestAccVSphereVirtualMachine_createWithFolder(t *testing.T) {
var vm virtualMachine
var folderLocationOpt string
var f folder
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
folderLocationOpt = fmt.Sprintf(" datacenter = \"%s\"\n", v)
}
folder := "tf_test_cpureateWithFolder"
data := setupTemplateFuncDHCPData()
vmName := "vsphere_virtual_machine.with_folder"
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-folder"}.testCheckFuncBasic()
config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createWithFolder,
folder,
folderLocationOpt,
) + data.parseDHCPTemplateConfig()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createWithFolder+testAccCheckVSphereTemplate_dhcp)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineDestroy,
testAccCheckVSphereFolderDestroy,
),
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
testAccCheckVSphereFolderExists(vmName, &f),
resource.TestCheckResourceAttr(vmName, "folder", folder),
),
},
},
})
}
const testAccCheckVsphereVirtualMachineConfig_cdrom = `
resource "vsphere_virtual_machine" "with_cdrom" {
name = "terraform-test-with-cdrom"
cdrom {
datastore = "%s"
path = "%s"
}
`
func TestAccVSphereVirtualMachine_createWithCdrom(t *testing.T) {
var vm virtualMachine
// FIXME check that these exist
cdromDatastore := os.Getenv("VSPHERE_CDROM_DATASTORE")
cdromPath := os.Getenv("VSPHERE_CDROM_PATH")
vmName := "vsphere_virtual_machine.with_cdrom"
data := setupTemplateFuncDHCPData()
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-cdrom"}.testCheckFuncBasic()
config := fmt.Sprintf(
testAccCheckVsphereVirtualMachineConfig_cdrom,
cdromDatastore,
cdromPath,
) + data.parseDHCPTemplateConfig()
log.Printf("[DEBUG] template= %s", testAccCheckVsphereVirtualMachineConfig_cdrom)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
//resource.TestCheckResourceAttr(
// "vsphere_virtual_machine.with_cdrom", "disk.4088143748.template", template),
resource.TestCheckResourceAttr(vmName, "cdrom.#", "1"),
resource.TestCheckResourceAttr(vmName, "cdrom.0.datastore", cdromDatastore),
resource.TestCheckResourceAttr(vmName, "cdrom.0.path", cdromPath),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_withExistingVmdk = `
resource "vsphere_virtual_machine" "with_existing_vmdk" {
name = "terraform-test-with-existing-vmdk"
%s
vcpu = 2
memory = 1024
network_interface {
label = "%s"
}
disk {
%s
vmdk = "%s"
bootable = true
}
disk {
size = 1
iops = 500
name = "one"
}
}
`
func TestAccVSphereVirtualMachine_createWithExistingVmdk(t *testing.T) {
var vm virtualMachine
vmdk_path := os.Getenv("VSPHERE_VMDK_PATH")
data := setupTemplateFuncDHCPData()
config := fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_withExistingVmdk,
data.locationOpt,
data.label,
data.datastoreOpt,
vmdk_path,
)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_withExistingVmdk)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.with_existing_vmdk",
vmResource: "terraform-test-with-existing-vmdk", numDisks: "2"}.testCheckFuncBasic(),
//resource.TestCheckResourceAttr(
// "vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.vmdk", vmdk_path),
//resource.TestCheckResourceAttr(
// "vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.bootable", "true"),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_updateMemory = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = 2
memory = %s
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
func TestAccVSphereVirtualMachine_updateMemory(t *testing.T) {
var vm virtualMachine
data := setupTemplateFuncDHCPData()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateMemory)
config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "1024")
log.Printf("[DEBUG] template config= %s", config)
configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "2048")
log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
),
},
resource.TestStep{
Config: configUpdate,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, mem: "2048", vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_updateVcpu = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = %s
memory = 1024
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
func TestAccVSphereVirtualMachine_updateVcpu(t *testing.T) {
var vm virtualMachine
data := setupTemplateFuncDHCPData()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateVcpu)
config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "2")
log.Printf("[DEBUG] template config= %s", config)
configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "4")
log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
),
},
resource.TestStep{
Config: configUpdate,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar", numCPU: "4"}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6 = `
resource "vsphere_virtual_machine" "ipv4ipv6" {
name = "terraform-test-ipv4-ipv6"
%s
vcpu = 2
memory = 1024
network_interface {
label = "%s"
ipv4_address = "%s"
ipv4_prefix_length = %s
ipv4_gateway = "%s"
ipv6_address = "%s"
ipv6_prefix_length = 64
ipv6_gateway = "%s"
}
disk {
%s
template = "%s"
iops = 500
}
disk {
size = 1
iops = 500
name = "one"
}
}
`
func TestAccVSphereVirtualMachine_ipv4Andipv6(t *testing.T) {
var vm virtualMachine
data := setupTemplateBasicBodyVars()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6)
vmName := "vsphere_virtual_machine.ipv4ipv6"
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "2", vmResource: "terraform-test-ipv4-ipv6"}.testCheckFuncBasic()
// FIXME test for this or warn??
ipv6Address := os.Getenv("VSPHERE_IPV6_ADDRESS")
ipv6Gateway := os.Getenv("VSPHERE_IPV6_GATEWAY")
config := fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6,
data.locationOpt,
data.label,
data.ipv4IpAddress,
data.ipv4Prefix,
data.ipv4Gateway,
ipv6Address,
ipv6Gateway,
data.datastoreOpt,
data.template,
)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_address", data.ipv4IpAddress),
resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_gateway", data.ipv4Gateway),
resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_address", ipv6Address),
resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_gateway", ipv6Gateway),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_updateAddDisks = `
resource "vsphere_virtual_machine" "foo" {
name = "terraform-test"
` + testAccTemplateBasicBody + `
disk {
size = 1
iops = 500
name = "one"
}
disk {
size = 1
iops = 500
name = "two"
}
disk {
size = 1
iops = 500
name = "three"
}
}
`
const testAccCheckVSphereVirtualMachineConfig_basic = `
resource "vsphere_virtual_machine" "foo" {
name = "terraform-test"
` + testAccTemplateBasicBody + `
disk {
size = 1
iops = 500
name = "one"
}
}
`
func TestAccVSphereVirtualMachine_updateDisks(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config_basic := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_basic)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
log.Printf("[DEBUG] template config= %s", config_basic)
config_add := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_updateAddDisks)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
log.Printf("[DEBUG] template config= %s", config_add)
config_del := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic)
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic)
log.Printf("[DEBUG] template config= %s", config_del)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config_basic,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: basic_vars.label, numDisks: "2"}.testCheckFuncBasic(),
),
},
resource.TestStep{
Config: config_add,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: basic_vars.label, numDisks: "4"}.testCheckFuncBasic(),
),
},
resource.TestStep{
Config: config_del,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: basic_vars.label, numDisks: "1"}.testCheckFuncBasic(),
),
},
},
})
}
const testAccCheckVSphereVirtualMachineConfig_mac_address = `
resource "vsphere_virtual_machine" "mac_address" {
name = "terraform-mac-address"
%s
vcpu = 2
memory = 1024
network_interface {
label = "%s"
mac_address = "%s"
}
disk {
%s
template = "%s"
}
}
`
// VSPHERE_NETWORK_MAC_ADDRESS needs to be set to run TestAccVSphereVirtualMachine_mac_address
// use a basic NIC MAC address like 6:5c:89:2b:a0:64
func testMacPreCheck(t *testing.T) {
testBasicPreCheck(t)
// TODO should start do parse values to ensure they are correct
// for instance
// func ParseMAC(s string) (hw HardwareAddr, err error)
if v := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS"); v == "" {
t.Fatal("env variable VSPHERE_NETWORK_MAC_ADDRESS must be set for this acceptance test")
}
}
// test new mac address feature
func TestAccVSphereVirtualMachine_mac_address(t *testing.T) {
var vm virtualMachine
data := setupTemplateFuncDHCPData()
vmName := "vsphere_virtual_machine.mac_address"
macAddress := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS")
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_mac_address)
config := fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_mac_address,
data.locationOpt,
data.label,
macAddress,
data.datastoreOpt,
data.template,
)
log.Printf("[DEBUG] template config= %s", config)
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "1", vmResource: "terraform-mac-address"}.testCheckFuncBasic()
resource.Test(t, resource.TestCase{
PreCheck: func() { testMacPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
resource.TestCheckResourceAttr(vmName, "network_interface.0.mac_address", macAddress),
),
},
},
})
}
func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
for _, rs := range s.RootModule().Resources {
if rs.Type != "vsphere_virtual_machine" {
continue
}
dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
if err != nil {
return fmt.Errorf("error %s", err)
}
dcFolders, err := dc.Folders(context.TODO())
if err != nil {
return fmt.Errorf("error %s", err)
}
folder := dcFolders.VmFolder
if len(rs.Primary.Attributes["folder"]) > 0 {
si := object.NewSearchIndex(client.Client)
folderRef, err := si.FindByInventoryPath(
context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
if err != nil {
return err
} else if folderRef != nil {
folder = folderRef.(*object.Folder)
}
}
v, err := object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
if v != nil {
return fmt.Errorf("Record still exists")
}
}
return nil
}
func testAccCheckVSphereVirtualMachineExistsHasCustomConfig(n string, vm *virtualMachine) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
if err != nil {
return fmt.Errorf("error %s", err)
}
dcFolders, err := dc.Folders(context.TODO())
if err != nil {
return fmt.Errorf("error %s", err)
}
_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), dcFolders.VmFolder, rs.Primary.Attributes["name"])
if err != nil {
return fmt.Errorf("error %s", err)
}
finder = finder.SetDatacenter(dc)
instance, err := finder.VirtualMachine(context.TODO(), rs.Primary.Attributes["name"])
if err != nil {
return fmt.Errorf("error %s", err)
}
var mvm mo.VirtualMachine
collector := property.DefaultCollector(client.Client)
if err := collector.RetrieveOne(context.TODO(), instance.Reference(), []string{"config.extraConfig"}, &mvm); err != nil {
return fmt.Errorf("error %s", err)
}
var configMap = make(map[string]types.AnyType)
if mvm.Config != nil && mvm.Config.ExtraConfig != nil && len(mvm.Config.ExtraConfig) > 0 {
for _, v := range mvm.Config.ExtraConfig {
value := v.GetOptionValue()
configMap[value.Key] = value.Value
}
} else {
return fmt.Errorf("error no ExtraConfig")
}
if configMap["foo"] == nil {
return fmt.Errorf("error no ExtraConfig for 'foo'")
}
if configMap["foo"] != "bar" {
return fmt.Errorf("error ExtraConfig 'foo' != bar")
}
if configMap["car"] == nil {
return fmt.Errorf("error no ExtraConfig for 'car'")
}
if configMap["car"] != "ferrari" {
return fmt.Errorf("error ExtraConfig 'car' != ferrari")
}
if configMap["num"] == nil {
return fmt.Errorf("error no ExtraConfig for 'num'")
}
// todo this should be an int, getting back a string
if configMap["num"] != "42" {
return fmt.Errorf("error ExtraConfig 'num' != 42")
}
*vm = virtualMachine{
name: rs.Primary.ID,
}
return nil
}
}
func testAccCheckDebugExists() resource.TestCheckFunc {
return func(s *terraform.State) error {
if _, err := os.Stat(filepath.Join(os.Getenv("HOME"), ".govmomi")); os.IsNotExist(err) {
return fmt.Errorf("Debug logs not found")
}
return nil
}
}
func testAccCheckVSphereVirtualMachineExists(n string, vm *virtualMachine) resource.TestCheckFunc {
return func(s *terraform.State) error {
if n == "" {
return fmt.Errorf("No vm name passed in")
}
if vm == nil {
return fmt.Errorf("No vm obj passed in")
}
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
if err != nil {
return fmt.Errorf("error %s", err)
}
dcFolders, err := dc.Folders(context.TODO())
if err != nil {
return fmt.Errorf("error %s", err)
}
folder := dcFolders.VmFolder
if len(rs.Primary.Attributes["folder"]) > 0 {
si := object.NewSearchIndex(client.Client)
folderRef, err := si.FindByInventoryPath(
context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
if err != nil {
return err
} else if folderRef != nil {
folder = folderRef.(*object.Folder)
}
}
_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
*vm = virtualMachine{
name: rs.Primary.ID,
}
return nil
}
}
const testAccCheckVSphereVirtualMachineConfig_keepOnRemove = `
resource "vsphere_virtual_machine" "keep_disk" {
name = "terraform-test"
` + testAccTemplateBasicBody + `
disk {
size = 1
iops = 500
controller_type = "scsi"
name = "one"
keep_on_remove = true
}
}
`
func TestAccVSphereVirtualMachine_keepOnRemove(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
var datastore string
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
datastore = v
}
var datacenter string
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
datacenter = v
}
vmName := "vsphere_virtual_machine.keep_disk"
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "2"}.testCheckFuncBasic()
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
log.Printf("[DEBUG] template config= %s", config)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
),
},
resource.TestStep{
Config: " ",
Check: checkForDisk(datacenter, datastore, "terraform-test", "one.vmdk"),
},
},
})
}
func checkForDisk(datacenter string, datastore string, vmName string, path string) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
dc, err := getDatacenter(client, datacenter)
if err != nil {
return err
}
finder.SetDatacenter(dc)
ds, err := finder.Datastore(context.TODO(), datastore)
if err != nil {
log.Printf("[ERROR] checkForDisk - Couldn't find Datastore '%v': %v", datastore, err)
return err
}
diskPath := vmName + "/" + path
_, err = ds.Stat(context.TODO(), diskPath)
if err != nil {
log.Printf("[ERROR] checkForDisk - Couldn't stat file '%v': %v", diskPath, err)
return err
}
// Cleanup
fileManager := object.NewFileManager(client.Client)
task, err := fileManager.DeleteDatastoreFile(context.TODO(), ds.Path(vmName), dc)
if err != nil {
log.Printf("[ERROR] checkForDisk - Couldn't delete vm folder '%v': %v", vmName, err)
return err
}
_, err = task.WaitForResult(context.TODO(), nil)
if err != nil {
log.Printf("[ERROR] checForDisk - Failed while deleting vm folder '%v': %v", vmName, err)
return err
}
return nil
}
}