From 6873d8dc1226095bba9b12a367ce8736170618d8 Mon Sep 17 00:00:00 2001 From: sam Date: Tue, 14 Jan 2025 15:36:27 +0000 Subject: [PATCH] Add import datastore The syntax is: ``` terraform import hpegl_pc_datastore.my_datastore , ``` For example: ``` terraform -chdir=examples import hpegl_pc_datastore.my_datastore \ 126fd201-9e6e-5e31-9ffb-a766265b1fd3,698de955-87b5-5fe6-b683-78c3948beede ``` See https://developer.hashicorp.com/terraform/plugin/framework/resources/import for related information. --- Makefile | 5 ++- internal/resources/datastore/resource.go | 53 +++++++++++++++++++++++- test/datastore/datastore_test.go | 35 +++++++++++++++- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6404945..552c006 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,10 @@ demo: env TF_LOG=INFO env TF_CLI_CONFIG_FILE=$$tfconfig \ terraform -chdir=examples apply -auto-approve; \ env TF_LOG=INFO env TF_CLI_CONFIG_FILE=$$tfconfig \ - terraform -chdir=examples destroy -auto-approve + terraform -chdir=examples destroy -auto-approve; \ + env TF_LOG=INFO env TF_CLI_CONFIG_FILE=$$tfconfig \ + terraform -chdir=examples import hpegl_pc_datastore.my_datastore \ + 126fd201-9e6e-5e31-9ffb-a766265b1fd3,698de955-87b5-5fe6-b683-78c3948beede lint: @golangci-lint --version diff --git a/internal/resources/datastore/resource.go b/internal/resources/datastore/resource.go index 093dd88..66ede32 100644 --- a/internal/resources/datastore/resource.go +++ b/internal/resources/datastore/resource.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "path" + "strings" "github.com/HewlettPackard/hpegl-pcbe-terraform-resources/internal/async" "github.com/HewlettPackard/hpegl-pcbe-terraform-resources/internal/client" @@ -211,6 +212,27 @@ func doRead( (*dataP).CapacityInBytes = types.Int64Value(*capacityInBytes) + datastoreType := datastore.GetAdditionalData()["datastoreType"] + if datastoreType == nil { + (*diagsP).AddError( + "error reading datastore", + "'datastoreType' is nil", + ) + + return + } + + datastoreTypeString, ok := datastoreType.(*string) + if !ok { + (*diagsP).AddError( + "error reading datastore", + "'datastoreType' is invalid", + ) + + return + } + (*dataP).DatastoreType = types.StringValue(*datastoreTypeString) + datacentersInfo := datastore.GetDatacentersInfo() if datacentersInfo == nil { (*diagsP).AddError( @@ -588,10 +610,39 @@ func (r *Resource) Delete( } } +// Import only grants access to a single "ID" parameter. Therefore, we have to +// combine the "hci_cluster_uuid" and datastore "id" values into the single +// req.ID string +func parseImportID( + id string, +) (clusterID string, datastoreID string, error error) { + params := strings.Split(id, ",") + if len(params) != 2 || params[0] == "" || params[1] == "" { + return "", "", errors.New("invalid import ID format") + } + + return params[0], params[1], nil +} + func (r *Resource) ImportState( ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse, ) { - resource.ImportStatePassthroughID(ctx, tfpath.Root("id"), req, resp) + clusterID, datastoreID, err := parseImportID(req.ID) + if err != nil { + resp.Diagnostics.AddError( + "import has invalid datastore id format", + "Provided import ID \""+req.ID+"\" is invalid. "+ + "Format must be \",\". For example: "+ + "f8d3e2fd-a0e0-41a3-83b3-a8f92b21a9f3,e8beff7c-6fc8-42f4-bb9f-8e2935d69918", + ) + + return + } + + diags := resp.State.SetAttribute(ctx, tfpath.Root("id"), datastoreID) + resp.Diagnostics.Append(diags...) + diags = resp.State.SetAttribute(ctx, tfpath.Root("hci_cluster_uuid"), clusterID) + resp.Diagnostics.Append(diags...) } diff --git a/test/datastore/datastore_test.go b/test/datastore/datastore_test.go index a0118d2..e8b7f73 100644 --- a/test/datastore/datastore_test.go +++ b/test/datastore/datastore_test.go @@ -62,6 +62,17 @@ func checkUUIDAttr(resource string, attr string) func(*terraform.State) error { } } +func testAccCheckResourceDestroyed(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Check if the resource is in the state + if rs, ok := s.RootModule().Resources[resourceName]; ok { + return fmt.Errorf("Resource %s still exists: %v", resourceName, rs.Primary.ID) + } + + return nil + } +} + func TestAccDatastoreResourceOk(t *testing.T) { config := providerConfig + ` resource "hpegl_pc_datastore" "test" { @@ -74,7 +85,6 @@ func TestAccDatastoreResourceOk(t *testing.T) { } } ` - checks := []resource.TestCheckFunc{ resource.TestCheckResourceAttr( "hpegl_pc_datastore.test", @@ -126,6 +136,29 @@ func TestAccDatastoreResourceOk(t *testing.T) { PlanOnly: true, ExpectNonEmptyPlan: false, }, + { + // Destroy by specifying empty config + Config: providerConfig, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckResourceDestroyed("hpegl_pc_datastore.test"), + ), + }, + { + // Import + Check: checkFn, + Config: config, + ImportState: true, + ResourceName: "hpegl_pc_datastore.test", + ImportStateId: "126fd201-9e6e-5e31-9ffb-a766265b1fd3,698de955-87b5-5fe6-b683-78c3948beede", + ImportStatePersist: true, + }, + { + // Check post import state matches the resource config + // e.g. verfies 'name' in state matches 'name' in config + Config: config, + Check: checkFn, + ExpectNonEmptyPlan: false, + }, }, }) }