diff --git a/.changelog/0.13.0.toml b/.changelog/0.13.0.toml index 49897478..eb5ea0c3 100644 --- a/.changelog/0.13.0.toml +++ b/.changelog/0.13.0.toml @@ -11,5 +11,5 @@ title = "" description = "" [[bugs]] -title = "" -description = "" +title = "`oxide_instance`" +description = "Fixed a provider crash when applying a configuration with an empty `boot_disk_id` attribute and a non-empty `disk_attachments` attribute. [#471](https://github.com/oxidecomputer/terraform-provider-oxide/pull/471)" diff --git a/internal/provider/resource_instance.go b/internal/provider/resource_instance.go index 1131c60a..1473a782 100644 --- a/internal/provider/resource_instance.go +++ b/internal/provider/resource_instance.go @@ -1216,6 +1216,10 @@ func newDiskAttachmentsOnCreate(ctx context.Context, client *oxide.Client, diskI } func filterBootDiskFromDisks(disks []oxide.InstanceDiskAttachment, boot_disk *oxide.InstanceDiskAttachment) []oxide.InstanceDiskAttachment { + if boot_disk == nil { + return disks + } + var filtered_disks = []oxide.InstanceDiskAttachment{} for _, disk := range disks { if disk == *boot_disk { diff --git a/internal/provider/resource_instance_test.go b/internal/provider/resource_instance_test.go index ae059a14..1b4799a7 100644 --- a/internal/provider/resource_instance_test.go +++ b/internal/provider/resource_instance_test.go @@ -835,6 +835,81 @@ resource "oxide_instance" "{{.BlockName}}" { }) } +func TestAccCloudResourceInstance_no_boot_disk(t *testing.T) { + type resourceInstanceNoBootDiskConfig struct { + BlockName string + InstanceName string + DiskBlockName string + DiskName string + SupportBlockName string + } + + resourceInstanceNoBootDiskConfigTpl := ` +data "oxide_project" "{{.SupportBlockName}}" { + name = "tf-acc-test" +} + +resource "oxide_disk" "{{.DiskBlockName}}" { + project_id = data.oxide_project.{{.SupportBlockName}}.id + description = "a test disk" + name = "{{.DiskName}}" + size = 1073741824 + block_size = 512 +} + +resource "oxide_instance" "{{.BlockName}}" { + project_id = data.oxide_project.{{.SupportBlockName}}.id + description = "a test instance" + name = "{{.InstanceName}}" + host_name = "terraform-acc-myhost" + memory = 1073741824 + ncpus = 1 + start_on_create = false + disk_attachments = [oxide_disk.{{.DiskBlockName}}.id] +} +` + + instanceName := newResourceName() + diskName := newResourceName() + blockName := newBlockName("instance-no-boot-disk") + diskBlockName := newBlockName("disk") + supportBlockName := newBlockName("support") + resourceName := fmt.Sprintf("oxide_instance.%s", blockName) + config, err := parsedAccConfig( + resourceInstanceNoBootDiskConfig{ + BlockName: blockName, + InstanceName: instanceName, + DiskBlockName: diskBlockName, + DiskName: diskName, + SupportBlockName: supportBlockName, + }, + resourceInstanceNoBootDiskConfigTpl, + ) + if err != nil { + t.Errorf("error parsing config template data: %e", err) + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(), + CheckDestroy: testAccInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: checkResourceInstanceNoBootDisk(resourceName, instanceName), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + // This option is only relevant for create, this means that it will + // never be imported + ImportStateVerifyIgnore: []string{"start_on_create"}, + }, + }, + }) +} + func TestAccCloudResourceInstance_antiAffinityGroups(t *testing.T) { type resourceInstanceAntiAffinityGroupsConfig struct { BlockName string @@ -1281,6 +1356,23 @@ func checkResourceInstanceAntiAffinityGroupsUpdate(resourceName, instanceName st }...) } +func checkResourceInstanceNoBootDisk(resourceName, instanceName string) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", "a test instance"), + resource.TestCheckResourceAttr(resourceName, "name", instanceName), + resource.TestCheckResourceAttr(resourceName, "host_name", "terraform-acc-myhost"), + resource.TestCheckResourceAttr(resourceName, "memory", "1073741824"), + resource.TestCheckResourceAttr(resourceName, "ncpus", "1"), + resource.TestCheckResourceAttr(resourceName, "start_on_create", "false"), + resource.TestCheckNoResourceAttr(resourceName, "boot_disk_id"), + resource.TestCheckResourceAttrSet(resourceName, "disk_attachments.0"), + resource.TestCheckResourceAttrSet(resourceName, "project_id"), + resource.TestCheckResourceAttrSet(resourceName, "time_created"), + resource.TestCheckResourceAttrSet(resourceName, "time_modified"), + }...) +} + func testAccInstanceDestroy(s *terraform.State) error { client, err := newTestClient() if err != nil {