diff --git a/docs/resources/vdb_group.md b/docs/resources/vdb_group.md index 60862ba..640e742 100644 --- a/docs/resources/vdb_group.md +++ b/docs/resources/vdb_group.md @@ -10,6 +10,14 @@ Creating a vdb group and assigning vdb with vdb_id = my_vdb_id resource "delphix_vdb_group" "vdb_group_name" { name = "my vdb group" vdb_ids = ["my_vdb_id"] + tags { + key = "environment" + value = "production" + } + tags { + key = "project" + value = "terraform" + } } ``` @@ -21,6 +29,10 @@ resource "delphix_vdb_group" "vdb_group_name" { * `vdb_ids` - The list of VDB IDs in this VDBGroup. +* `tags` - The tags to be created for the VDB group. This is a map of 2 parameters: + * `key` - The key of the tag. + * `value` - The value of the tag. + ## Attribute Reference This resource exports same attributes as the arguments. diff --git a/examples/vdb_group/main.tf b/examples/vdb_group/main.tf index ca10dd1..3243a53 100644 --- a/examples/vdb_group/main.tf +++ b/examples/vdb_group/main.tf @@ -48,4 +48,12 @@ resource "delphix_vdb" "vdb_provision_loop" { resource "delphix_vdb_group" "this" { name = "random" vdb_ids = sort(flatten([for vdb in delphix_vdb.example : vdb.id])) + tags { + key = "environment" + value = "production" + } + tags { + key = "project" + value = "terraform" + } } diff --git a/go.mod b/go.mod index b1f941a..a6a5a9b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 toolchain go1.22.6 require ( - github.com/delphix/dct-sdk-go/v25 v25.1.2 + github.com/delphix/dct-sdk-go/v25 v25.2.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 ) diff --git a/go.sum b/go.sum index 58923b1..c4b0777 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/delphix/dct-sdk-go/v25 v25.1.2 h1:wiJui4cZB4xK9Znu9JdWb5N3rKqbnz1oXWaqLXjGHnE= github.com/delphix/dct-sdk-go/v25 v25.1.2/go.mod h1:Y//bIbAZP6SZhLLZAQMxEfeRXvsvKQwu/kSR8a5hfqc= +github.com/delphix/dct-sdk-go/v25 v25.2.0 h1:djFGvJwDHE99vBFa5ZlixcV49niz7nRsuwfue8l/AQA= +github.com/delphix/dct-sdk-go/v25 v25.2.0/go.mod h1:fCw+bOFPHiNcqUGvRpOEq4PINgcmw6KptstJy4v66Uo= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= diff --git a/internal/provider/resource_vdb_group.go b/internal/provider/resource_vdb_group.go index 5027d38..9e575f3 100644 --- a/internal/provider/resource_vdb_group.go +++ b/internal/provider/resource_vdb_group.go @@ -2,6 +2,7 @@ package provider import ( "context" + "time" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -18,6 +19,9 @@ func resourceVdbGroup() *schema.Resource { ReadContext: resourceVdbGroupRead, UpdateContext: resourceVdbGroupUpdate, DeleteContext: resourceVdbGroupDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, Schema: map[string]*schema.Schema{ "id": { @@ -35,18 +39,39 @@ func resourceVdbGroup() *schema.Resource { Type: schema.TypeString, }, }, + "tags": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, }, } } func resourceVdbGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics client := meta.(*apiClient).client vdbGroupCreateReq := *dctapi.NewCreateVDBGroupRequest(d.Get("name").(string)) vdbGroupCreateReq.SetVdbIds(toStringArray(d.Get("vdb_ids"))) + + if v, has_v := d.GetOk("tags"); has_v { + vdbGroupCreateReq.SetTags(toTagArray(v)) + } + apiRes, httpRes, err := client.VDBGroupsAPI.CreateVdbGroup(ctx).CreateVDBGroupRequest(vdbGroupCreateReq).Execute() if diags := apiErrorResponseHelper(ctx, apiRes, httpRes, err); diags != nil { @@ -64,7 +89,6 @@ func resourceVdbGroupCreate(ctx context.Context, d *schema.ResourceData, meta in } func resourceVdbGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*apiClient).client var diags diag.Diagnostics @@ -80,12 +104,151 @@ func resourceVdbGroupRead(ctx context.Context, d *schema.ResourceData, meta inte d.Set("name", apiRes.GetName()) d.Set("vdb_ids", apiRes.GetVdbIds()) + d.Set("tags", flattenTags(apiRes.GetTags())) return diags } func resourceVdbGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*apiClient).client + vdbGroupId := d.Id() + + // Existing update logic + updateVdbGroupReq := *dctapi.NewUpdateVDBGroupParameters() + if d.HasChange("name") { + updateVdbGroupReq.SetName(d.Get("name").(string)) + } + if d.HasChange("vdb_ids") { + updateVdbGroupReq.SetVdbIds(toStringArray(d.Get("vdb_ids"))) + } + + _, httpRes, err := client.VDBGroupsAPI.UpdateVdbGroupById(ctx, vdbGroupId).UpdateVDBGroupParameters(updateVdbGroupReq).Execute() + if diags := apiErrorResponseHelper(ctx, nil, httpRes, err); diags != nil { + return diags + } - return diag.Errorf("not implemented") + // Polling logic for name/vdb_ids update + maxAttempts := 10 + for attempt := 1; attempt <= maxAttempts; attempt++ { + status, err := PollVdbGroupStatus(ctx, client, vdbGroupId) + if err != nil { + return diag.FromErr(err) + } + if status == "RUNNING" { + break + } + if status == "FAILED" || status == "CANCELED" { + return diag.Errorf("VDB group update failed with status: %s", status) + } + time.Sleep(time.Duration(STATUS_POLL_SLEEP_TIME) * time.Second) + } + + // Tag update logic + if d.HasChange("tags") { + oldTags, newTags := d.GetChange("tags") + oldTagList := oldTags.([]interface{}) + newTagList := newTags.([]interface{}) + + // Create a map of old tags for easy lookup + oldTagMap := make(map[string]map[string]bool) + for _, tag := range oldTagList { + tagMap := tag.(map[string]interface{}) + key := tagMap["key"].(string) + value := tagMap["value"].(string) + if _, exists := oldTagMap[key]; !exists { + oldTagMap[key] = make(map[string]bool) + } + oldTagMap[key][value] = true + } + + // Create a map of new tags for easy lookup + newTagMap := make(map[string]map[string]bool) + for _, tag := range newTagList { + tagMap := tag.(map[string]interface{}) + key := tagMap["key"].(string) + value := tagMap["value"].(string) + if _, exists := newTagMap[key]; !exists { + newTagMap[key] = make(map[string]bool) + } + newTagMap[key][value] = true + } + + // If newTagList is empty, delete all existing tags + if len(newTagList) == 0 { + for key := range oldTagMap { + deleteTag := *dctapi.NewDeleteTag() + deleteTag.SetKey(key) + httpRes, err := client.VDBGroupsAPI.DeleteVdbGroupTags(ctx, vdbGroupId).DeleteTag(deleteTag).Execute() + if diags := apiErrorResponseHelper(ctx, nil, httpRes, err); diags != nil { + return diags + } + } + } else { + // Delete removed tags + for key, oldValues := range oldTagMap { + newValues, exists := newTagMap[key] + if !exists { + // Key doesn't exist in new tags, delete all values for this key + deleteTag := *dctapi.NewDeleteTag() + deleteTag.SetKey(key) + httpRes, err := client.VDBGroupsAPI.DeleteVdbGroupTags(ctx, vdbGroupId).DeleteTag(deleteTag).Execute() + if diags := apiErrorResponseHelper(ctx, nil, httpRes, err); diags != nil { + return diags + } + } else { + // Key exists, delete only values that are not in new tags + for oldValue := range oldValues { + if !newValues[oldValue] { + deleteTag := *dctapi.NewDeleteTag() + deleteTag.SetKey(key) + deleteTag.SetValue(oldValue) + httpRes, err := client.VDBGroupsAPI.DeleteVdbGroupTags(ctx, vdbGroupId).DeleteTag(deleteTag).Execute() + if diags := apiErrorResponseHelper(ctx, nil, httpRes, err); diags != nil { + return diags + } + } + } + } + } + + // Create new tags + var tags []dctapi.Tag + for key, newValues := range newTagMap { + oldValues, exists := oldTagMap[key] + if !exists { + // Key doesn't exist in old tags, create all values + for value := range newValues { + tag := *dctapi.NewTag(key, value) + tags = append(tags, tag) + } + } else { + // Key exists, create only new values + for value := range newValues { + if !oldValues[value] { + tag := *dctapi.NewTag(key, value) + tags = append(tags, tag) + } + } + } + } + if len(tags) > 0 { + tagsRequest := *dctapi.NewTagsRequest(tags) + _, httpRes, err := client.VDBGroupsAPI.CreateVdbGroupsTags(ctx, vdbGroupId).TagsRequest(tagsRequest).Execute() + if diags := apiErrorResponseHelper(ctx, nil, httpRes, err); diags != nil { + return diags + } + } + } + } + + return resourceVdbGroupRead(ctx, d, meta) +} + +func PollVdbGroupStatus(ctx context.Context, client *dctapi.APIClient, vdbGroupId string) (string, error) { + res, _, err := client.VDBGroupsAPI.GetVdbGroup(ctx, vdbGroupId).Execute() + if err != nil { + return "", err + } + return res.GetStatus(), nil } func resourceVdbGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diff --git a/internal/provider/resource_vdb_group_test.go b/internal/provider/resource_vdb_group_test.go index 83e8738..e50e4db 100644 --- a/internal/provider/resource_vdb_group_test.go +++ b/internal/provider/resource_vdb_group_test.go @@ -11,7 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccVdb_create_vdb_group_positive(t *testing.T) { +// TestAccVdbGroup_create_positive tests the basic creation of a VDB group with a single VDB +func TestAccVdbGroup_create_positive(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccVdbPreCheck(t) }, Providers: testAccProviders, @@ -26,20 +27,348 @@ func TestAccVdb_create_vdb_group_positive(t *testing.T) { }) } +// TestAccVdbGroup_tags tests various tag management scenarios: +// 1. Initial tag creation with multiple tags (including multiple values for same key) +// 2. Tag updates including: +// - Modifying an existing tag's value (environment: test -> prod) +// - Adding a new tag (owner: team-a) +// - Removing a tag (purpose: testing) +// +// 3. Complete tag removal (setting tags to empty) +func TestAccVdbGroup_tags(t *testing.T) { + var vdbGroupId string + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccVdbPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVdbGroupDestroy, + Steps: []resource.TestStep{ + { + // Create VDB group with initial tags + Config: testAccCheckDctVDBGroupConfigWithTags(), + Check: resource.ComposeTestCheckFunc( + testAccCheckDctVdbGroupResourceExists("delphix_vdb.test", "delphix_vdb_group.test"), + resource.TestCheckResourceAttr("delphix_vdb_group.test", "tags.#", "3"), + resource.TestCheckTypeSetElemNestedAttrs("delphix_vdb_group.test", "tags.*", map[string]string{ + "key": "environment", + "value": "test", + }), + resource.TestCheckTypeSetElemNestedAttrs("delphix_vdb_group.test", "tags.*", map[string]string{ + "key": "environment", + "value": "dev", + }), + resource.TestCheckTypeSetElemNestedAttrs("delphix_vdb_group.test", "tags.*", map[string]string{ + "key": "purpose", + "value": "testing", + }), + // Store the VDB group ID for later verification + func(s *terraform.State) error { + rs, ok := s.RootModule().Resources["delphix_vdb_group.test"] + if !ok { + return fmt.Errorf("Not found: delphix_vdb_group.test") + } + vdbGroupId = rs.Primary.ID + return nil + }, + ), + }, + { + // Update tags - add new tag, modify existing tag, remove tag + Config: testAccCheckDctVDBGroupConfigWithTagsUpdated(), + ImportStateVerify: true, + ImportState: true, + ResourceName: "delphix_vdb_group.test", + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "tags.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs("delphix_vdb_group.test", "tags.*", map[string]string{ + "key": "environment", + "value": "prod", + }), + resource.TestCheckTypeSetElemNestedAttrs("delphix_vdb_group.test", "tags.*", map[string]string{ + "key": "owner", + "value": "team-a", + }), + // Verify the VDB group ID hasn't changed + resource.TestCheckResourceAttr("delphix_vdb_group.test", "id", vdbGroupId), + ), + }, + { + // Remove all tags + Config: testAccCheckDctVDBGroupConfigBasicWithName("my-vdb-group-name-2"), + ImportStateVerify: true, + ImportState: true, + ResourceName: "delphix_vdb_group.test", + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "tags.#", "0"), + // Verify the VDB group ID hasn't changed + resource.TestCheckResourceAttr("delphix_vdb_group.test", "id", vdbGroupId), + ), + }, + }, + }) +} + +// TestAccVdbGroup_update_name tests the ability to rename a VDB group +func TestAccVdbGroup_update_name(t *testing.T) { + var vdbGroupId string + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccVdbPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVdbGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckDctVDBGroupConfigBasicWithName("my-vdb-group-original"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "name", "my-vdb-group-original"), + // Store the VDB group ID for later verification + func(s *terraform.State) error { + rs, ok := s.RootModule().Resources["delphix_vdb_group.test"] + if !ok { + return fmt.Errorf("Not found: delphix_vdb_group.test") + } + vdbGroupId = rs.Primary.ID + return nil + }, + ), + }, + { + Config: testAccCheckDctVDBGroupConfigBasicWithName("my-vdb-group-renamed"), + ImportStateVerify: true, + ImportState: true, + ResourceName: "delphix_vdb_group.test", + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "name", "my-vdb-group-renamed"), + // Verify the VDB group ID hasn't changed + resource.TestCheckResourceAttr("delphix_vdb_group.test", "id", vdbGroupId), + ), + }, + }, + }) +} + +// TestAccVdbGroup_update_vdb_ids tests VDB group membership changes: +// 1. Initial creation with one VDB +// 2. Update to use a different VDB +// 3. Update to use multiple VDBs +func TestAccVdbGroup_update_vdb_ids(t *testing.T) { + var vdbGroupId string + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccVdbPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVdbGroupDestroy, + Steps: []resource.TestStep{ + { + // Create VDB group with first VDB + Config: testAccCheckDctVDBGroupConfigWithTwoVdbs("my-vdb-group-vdbid", "vdb3"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "vdb_ids.#", "1"), + resource.TestCheckResourceAttrPair("delphix_vdb_group.test", "vdb_ids.0", "delphix_vdb.vdb3", "id"), + // Store the VDB group ID for later verification + func(s *terraform.State) error { + rs, ok := s.RootModule().Resources["delphix_vdb_group.test"] + if !ok { + return fmt.Errorf("Not found: delphix_vdb_group.test") + } + vdbGroupId = rs.Primary.ID + return nil + }, + ), + }, + { + // Update to use second VDB + Config: testAccCheckDctVDBGroupConfigWithTwoVdbs("my-vdb-group-vdbid", "vdb4"), + ImportStateVerify: true, + ImportState: true, + ResourceName: "delphix_vdb_group.test", + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "vdb_ids.#", "1"), + resource.TestCheckResourceAttrPair("delphix_vdb_group.test", "vdb_ids.0", "delphix_vdb.vdb4", "id"), + // Verify the VDB group ID hasn't changed + resource.TestCheckResourceAttr("delphix_vdb_group.test", "id", vdbGroupId), + ), + }, + { + // Update to use both VDBs + Config: testAccCheckDctVDBGroupConfigWithMultipleVdbs("my-vdb-group-vdbid"), + ImportStateVerify: true, + ImportState: true, + ResourceName: "delphix_vdb_group.test", + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("delphix_vdb_group.test", "vdb_ids.#", "2"), + resource.TestCheckResourceAttrPair("delphix_vdb_group.test", "vdb_ids.0", "delphix_vdb.vdb3", "id"), + resource.TestCheckResourceAttrPair("delphix_vdb_group.test", "vdb_ids.1", "delphix_vdb.vdb4", "id"), + // Verify the VDB group ID hasn't changed + resource.TestCheckResourceAttr("delphix_vdb_group.test", "id", vdbGroupId), + ), + }, + }, + }) +} + +// Helper Functions + +// testAccCheckDctVDBGroupConfigBasic creates a basic VDB group with a single VDB func testAccCheckDctVDBGroupConfigBasic() string { datasource_id := os.Getenv("DATASOURCE_ID") return fmt.Sprintf(` resource "delphix_vdb" "new" { auto_select_repository = true source_data_id = "%s" + name = "TESTVDB1" + provision_type = "snapshot" } resource "delphix_vdb_group" "new_group" { - name = "my-vdb-group-name" + name = "my-vdb-group-name-1" vdb_ids = [delphix_vdb.new.id] } `, datasource_id) } +// testAccCheckDctVDBGroupConfigWithTags creates a VDB group with initial tags: +// - environment: test +// - environment: dev (multiple values for same key) +// - purpose: testing +func testAccCheckDctVDBGroupConfigWithTags() string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "test" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB2" + provision_type = "snapshot" + } + + resource "delphix_vdb_group" "test" { + name = "my-vdb-group-name-2" + vdb_ids = [delphix_vdb.test.id] + + tags { + key = "environment" + value = "test" + } + tags { + key = "environment" + value = "dev" + } + tags { + key = "purpose" + value = "testing" + } + } + `, datasource_id) +} + +// testAccCheckDctVDBGroupConfigWithTagsUpdated updates the tags to: +// - environment: prod (modified value) +// - owner: team-a (new tag) +// Note: purpose: testing is removed +func testAccCheckDctVDBGroupConfigWithTagsUpdated() string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "test" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB2" + provision_type = "snapshot" + } + + resource "delphix_vdb_group" "test" { + name = "my-vdb-group-name-2" + vdb_ids = [delphix_vdb.test.id] + + tags { + key = "environment" + value = "prod" + } + tags { + key = "owner" + value = "team-a" + } + } + `, datasource_id) +} + +// testAccCheckDctVDBGroupConfigBasicWithName creates a VDB group with no tags +// Used for testing tag removal and name updates +func testAccCheckDctVDBGroupConfigBasicWithName(groupName string) string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "test" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB2" + provision_type = "snapshot" + } + resource "delphix_vdb_group" "test" { + name = "%s" + vdb_ids = [delphix_vdb.test.id] + } + `, datasource_id, groupName) +} + +// testAccCheckDctVDBGroupConfigBasicWithVdbId creates a VDB group with a specific VDB +func testAccCheckDctVDBGroupConfigBasicWithVdbId(vdbName string, groupName string) string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "%s" { + auto_select_repository = true + source_data_id = "%s" + name = "%s" + provision_type = "snapshot" + } + resource "delphix_vdb_group" "test" { + name = "%s" + vdb_ids = [delphix_vdb.%s.id] + } + `, vdbName, datasource_id, vdbName, groupName, vdbName) +} + +// testAccCheckDctVDBGroupConfigWithTwoVdbs creates a VDB group with one of two possible VDBs +func testAccCheckDctVDBGroupConfigWithTwoVdbs(groupName, vdbName string) string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "vdb3" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB3" + provision_type = "snapshot" + } + resource "delphix_vdb" "vdb4" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB4" + provision_type = "snapshot" + } + resource "delphix_vdb_group" "test" { + name = "%s" + vdb_ids = [delphix_vdb.%s.id] + } + `, datasource_id, datasource_id, groupName, vdbName) +} + +// testAccCheckDctVDBGroupConfigWithMultipleVdbs creates a VDB group with multiple VDBs +func testAccCheckDctVDBGroupConfigWithMultipleVdbs(groupName string) string { + datasource_id := os.Getenv("DATASOURCE_ID") + return fmt.Sprintf(` + resource "delphix_vdb" "vdb3" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB3" + provision_type = "snapshot" + } + resource "delphix_vdb" "vdb4" { + auto_select_repository = true + source_data_id = "%s" + name = "TESTVDB4" + provision_type = "snapshot" + } + resource "delphix_vdb_group" "test" { + name = "%s" + vdb_ids = [delphix_vdb.vdb3.id, delphix_vdb.vdb4.id] + } + `, datasource_id, datasource_id, groupName) +} + +// testAccCheckDctVdbGroupResourceExists verifies that a VDB group exists and contains the expected VDB func testAccCheckDctVdbGroupResourceExists(vdbResourceName string, vdbGroupResourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { vdbGroupResource, ok := s.RootModule().Resources[vdbGroupResourceName] @@ -78,6 +407,7 @@ func testAccCheckDctVdbGroupResourceExists(vdbResourceName string, vdbGroupResou } } +// testAccCheckVdbGroupDestroy verifies that a VDB group has been properly destroyed func testAccCheckVdbGroupDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*apiClient).client diff --git a/internal/provider/utility.go b/internal/provider/utility.go index ba6248a..b599c8d 100644 --- a/internal/provider/utility.go +++ b/internal/provider/utility.go @@ -21,6 +21,8 @@ var SLEEP_TIME = 10 // Input is job status, context and the client // Returns the status of the given JOB-ID and Error body as a string func PollJobStatus(job_id string, ctx context.Context, client *dctapi.APIClient) (string, string) { + const maxRetries = 180 // 30 minutes with 10 second sleep + const sleepTime = 10 // seconds res, httpRes, err := client.JobsAPI.GetJobById(ctx, job_id).Execute() if err != nil { @@ -33,9 +35,12 @@ func PollJobStatus(job_id string, ctx context.Context, client *dctapi.APIClient) return "", resBody } - var i = 0 - for res.GetStatus() == Pending || res.GetStatus() == Started { - time.Sleep(time.Duration(JOB_STATUS_SLEEP_TIME) * time.Second) + for i := 0; i < maxRetries; i++ { + if res.GetStatus() != Pending && res.GetStatus() != Started { + return res.GetStatus(), res.GetErrorDetails() + } + + time.Sleep(time.Duration(sleepTime) * time.Second) res, httpRes, err = client.JobsAPI.GetJobById(ctx, job_id).Execute() if err != nil { if httpRes == nil { @@ -49,11 +54,10 @@ func PollJobStatus(job_id string, ctx context.Context, client *dctapi.APIClient) tflog.Error(ctx, DLPX+ERROR+err.Error()) return "", resBody } - i++ tflog.Info(ctx, DLPX+INFO+"DCT-JobId:"+job_id+" has Status:"+res.GetStatus()) } - return res.GetStatus(), res.GetErrorDetails() + return "", "Job polling timed out after " + strconv.Itoa(maxRetries*sleepTime) + " seconds" } // ResponseBodyToString parses the response body from io.readCloser() to string for