From 39033f778682d326f098f180e0b4c3584b8aecdd Mon Sep 17 00:00:00 2001 From: Dom Del Nano Date: Wed, 27 Dec 2023 17:25:01 -0800 Subject: [PATCH] Add tests to ensure power_state and destroy_cloud_config_vdi_after_boot don't clash --- xoa/resource_xenorchestra_vm.go | 14 +++++++++++++- xoa/resource_xenorchestra_vm_test.go | 25 +++++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/xoa/resource_xenorchestra_vm.go b/xoa/resource_xenorchestra_vm.go index d8da8b3d..9bed9035 100644 --- a/xoa/resource_xenorchestra_vm.go +++ b/xoa/resource_xenorchestra_vm.go @@ -1,6 +1,7 @@ package xoa import ( + "context" "errors" "fmt" "log" @@ -63,6 +64,16 @@ func resourceVm() *schema.Resource { } } +func vmDestroyCloudConfigCustomizeDiff(ctx context.Context, diff *schema.ResourceDiff, v interface{}) error { + destroyCloudConfig := diff.Get("destroy_cloud_config_vdi_after_boot").(bool) + powerState := diff.Get("power_state").(string) + + if destroyCloudConfig && powerState != client.RunningPowerState { + return errors.New(fmt.Sprintf("power_state must be `%s` when destroy_cloud_config_vdi_after_boot set to `true`", client.RunningPowerState)) + } + return nil +} + func resourceVmSchema() map[string]*schema.Schema { return map[string]*schema.Schema{ @@ -153,7 +164,7 @@ func resourceVmSchema() map[string]*schema.Schema { "cloud_config", }, ForceNew: true, - Description: "Determines whether the cloud config VDI should be deleted once the VM has booted. Defaults to `false`.", + Description: "Determines whether the cloud config VDI should be deleted once the VM has booted. Defaults to `false`. If set to `true`, power_state must be set to `Running`.", }, "core_os": &schema.Schema{ Type: schema.TypeBool, @@ -388,6 +399,7 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd func resourceRecord() *schema.Resource { duration := 5 * time.Minute return &schema.Resource{ + CustomizeDiff: vmDestroyCloudConfigCustomizeDiff, Description: "Creates a Xen Orchestra vm resource.", Create: resourceVmCreate, Read: resourceVmRead, diff --git a/xoa/resource_xenorchestra_vm_test.go b/xoa/resource_xenorchestra_vm_test.go index a0292530..de8f37e8 100644 --- a/xoa/resource_xenorchestra_vm_test.go +++ b/xoa/resource_xenorchestra_vm_test.go @@ -340,6 +340,22 @@ func TestAccXenorchestraVm_createWithShorterResourceTimeout(t *testing.T) { }) } +func TestAccXenorchestraVm_destroyCloudConfigRequiresRunningVm(t *testing.T) { + vmName := fmt.Sprintf("%s - %s", accTestPrefix, t.Name()) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckXenorchestraVmDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName, client.HaltedPowerState), + ExpectError: regexp.MustCompile("power_state must be `Running` when destroy_cloud_config_vdi_after_boot set to `true`"), + PlanOnly: true, + }, + }, + }) +} + func TestAccXenorchestraVm_createWithPowerStateChanges(t *testing.T) { resourceName := "xenorchestra_vm.bar" vmName := fmt.Sprintf("%s - %s", accTestPrefix, t.Name()) @@ -520,7 +536,7 @@ func TestAccXenorchestraVm_createWithDestroyCloudConfigDrive(t *testing.T) { CheckDestroy: testAccCheckXenorchestraVmDestroy, Steps: []resource.TestStep{ { - Config: testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName), + Config: testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName, client.RunningPowerState), Check: resource.ComposeAggregateTestCheckFunc( testAccVmExists(resourceName), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -529,7 +545,7 @@ func TestAccXenorchestraVm_createWithDestroyCloudConfigDrive(t *testing.T) { }, { PreConfig: verifyCloudConfigDiskDeleted, - Config: testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName), + Config: testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName, client.RunningPowerState), Check: resource.ComposeAggregateTestCheckFunc( testAccVmExists(resourceName), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -1929,7 +1945,7 @@ resource "xenorchestra_vm" "bar" { // the test expectations while the latter is to ensure the test holds its assertions until the // disk was actually deleted. The XO api uses the guest metrics to determine when it can remove // the disk, so an IP address allocation happens at the same time. -func testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName string) string { +func testAccVmConfigWithDestroyCloudConfigAfterBoot(vmName string, powerState string) string { return testAccCloudConfigConfig(fmt.Sprintf("vm-template-%s", vmName), "template") + testAccTemplateConfig() + fmt.Sprintf(` data "xenorchestra_network" "network" { name_label = "%s" @@ -1947,6 +1963,7 @@ resource "xenorchestra_vm" "bar" { network { network_id = "${data.xenorchestra_network.network.id}" } + power_state = "%s" wait_for_ip = true disk { @@ -1955,7 +1972,7 @@ resource "xenorchestra_vm" "bar" { size = 10001317888 } } -`, accDefaultNetwork.NameLabel, accTestPool.Id, vmName, accDefaultSr.Id) +`, accDefaultNetwork.NameLabel, accTestPool.Id, vmName, powerState, accDefaultSr.Id) } func testAccVmConfigPXEBoot(vmName string) string {