Skip to content

Commit 4fa21b9

Browse files
authored
Do not error when reading task related resource objects (#1500)
Previously if Workspace Run Tasks, Organiaztion Run Tasks or global settings were managed by TF and deleted server-side the TF apply/plan would error. However this stopped resources being removed or ignored. This commit modifies the Read methods to remove the previous resource state when the object no longer exists (a 404 response). The Read methods still raise if another error type is received (e.g. 500 or Network error).
1 parent 2fe452d commit 4fa21b9

7 files changed

+260
-2
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## Unreleased
22

3+
BUG FIXES:
4+
* `r/tfe_workspace_run_task`: Do not error when reading workspace tasks that no longer exist by @glennsarti [#1500](https://github.com/hashicorp/terraform-provider-tfe/pull/1459)
5+
* `r/tfe_organization_run_task`: Do not error when reading organization tasks that no longer exist by @glennsarti [#1500](https://github.com/hashicorp/terraform-provider-tfe/pull/1459)
6+
* `r/tfe_organization_run_task_global_settings`: Do not error when reading organization task global settings that no longer exist by @glennsarti [#1500](https://github.com/hashicorp/terraform-provider-tfe/pull/1459)
7+
8+
## v0.59.0
9+
310
## BREAKING CHANGES
411

512
* `r/tfe_team`: Default "secret" visibility has been removed from tfe_team because it now requires explicit or owner access. The default, "organization", is now computed by the platform. by @brandonc [#1439](https://github.com/hashicorp/terraform-provider-tfe/pull/1439)

internal/provider/helper_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ func createProject(t *testing.T, client *tfe.Client, orgName string, options tfe
187187
return proj
188188
}
189189

190+
func createRunTask(t *testing.T, client *tfe.Client, orgName string, options tfe.RunTaskCreateOptions) *tfe.RunTask {
191+
ctx := context.Background()
192+
193+
if options.Category == "" {
194+
options.Category = "task"
195+
}
196+
197+
task, err := client.RunTasks.Create(ctx, orgName, options)
198+
if err != nil {
199+
t.Fatal(err)
200+
return nil
201+
}
202+
203+
return task
204+
}
205+
190206
func skipIfCloud(t *testing.T) {
191207
if !enterpriseEnabled() {
192208
t.Skip("Skipping test for a feature unavailable in HCP Terraform. Set 'ENABLE_TFE=1' to run.")
@@ -270,6 +286,17 @@ func testCheckResourceAttrUnlessEnterprise(name, key, value string) resource.Tes
270286
return resource.TestCheckResourceAttr(name, key, value)
271287
}
272288

289+
// Tests whether a resource exists in the state
290+
func testCheckResourceNotExist(resourceName string) resource.TestCheckFunc {
291+
return func(s *terraform.State) error {
292+
if item, ok := s.RootModule().Resources[resourceName]; ok {
293+
return fmt.Errorf("Resource %s should not exist but found a resource with id %s", resourceName, item.Primary.ID)
294+
}
295+
296+
return nil
297+
}
298+
}
299+
273300
func randomString(t *testing.T) string {
274301
v, err := uuid.GenerateUUID()
275302
if err != nil {

internal/provider/resource_tfe_organization_run_task.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,11 @@ func (r *resourceOrgRunTask) Read(ctx context.Context, req resource.ReadRequest,
160160
tflog.Debug(ctx, "Reading organization run task")
161161
task, err := r.config.Client.RunTasks.Read(ctx, taskID)
162162
if err != nil {
163-
resp.Diagnostics.AddError("Error reading Organization Run Task", "Could not read Organization Run Task, unexpected error: "+err.Error())
163+
if errors.Is(err, tfe.ErrResourceNotFound) {
164+
resp.State.RemoveResource(ctx)
165+
} else {
166+
resp.Diagnostics.AddError("Error reading Organization Run Task", "Could not read Organization Run Task, unexpected error: "+err.Error())
167+
}
164168
return
165169
}
166170

internal/provider/resource_tfe_organization_run_task_global_settings_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,78 @@ func TestAccTFEOrganizationRunTaskGlobalSettings_import(t *testing.T) {
145145
})
146146
}
147147

148+
func TestAccTFEOrganizationRunTaskGlobalSettings_Read(t *testing.T) {
149+
skipUnlessRunTasksDefined(t)
150+
151+
tfeClient, err := getClientUsingEnv()
152+
if err != nil {
153+
t.Fatal(err)
154+
}
155+
156+
org, orgCleanup := createBusinessOrganization(t, tfeClient)
157+
t.Cleanup(orgCleanup)
158+
key := runTasksHMACKey()
159+
task := createRunTask(t, tfeClient, org.Name, tfe.RunTaskCreateOptions{
160+
Name: fmt.Sprintf("tst-task-%s", randomString(t)),
161+
URL: runTasksURL(),
162+
HMACKey: &key,
163+
})
164+
165+
org_tf := fmt.Sprintf(`data "tfe_organization" "orgtask" { name = %q }`, org.Name)
166+
167+
create_settings_tf := fmt.Sprintf(`
168+
%s
169+
resource "tfe_organization_run_task_global_settings" "sut" {
170+
task_id = %q
171+
172+
enabled = true
173+
enforcement_level = "mandatory"
174+
stages = ["post_plan"]
175+
}
176+
`, org_tf, task.ID)
177+
178+
delete_task_settings := func() {
179+
_, err := tfeClient.RunTasks.Update(ctx, task.ID, tfe.RunTaskUpdateOptions{
180+
Global: &tfe.GlobalRunTaskOptions{
181+
Enabled: tfe.Bool(false),
182+
},
183+
})
184+
if err != nil {
185+
t.Fatalf("Error updating task: %s", err)
186+
}
187+
}
188+
189+
resource.Test(t, resource.TestCase{
190+
PreCheck: func() { testAccPreCheck(t) },
191+
ProtoV5ProviderFactories: testAccMuxedProviders,
192+
CheckDestroy: testAccCheckTFEOrganizationRunTaskDestroy,
193+
Steps: []resource.TestStep{
194+
{
195+
Config: create_settings_tf,
196+
Check: resource.ComposeTestCheckFunc(
197+
resource.TestCheckResourceAttr("tfe_organization_run_task_global_settings.sut", "enabled", "true"),
198+
),
199+
},
200+
{
201+
// Delete the created run task settings and ensure we can re-create it
202+
PreConfig: delete_task_settings,
203+
Config: create_settings_tf,
204+
Check: resource.ComposeTestCheckFunc(
205+
resource.TestCheckResourceAttr("tfe_organization_run_task_global_settings.sut", "enabled", "true"),
206+
),
207+
},
208+
{
209+
// Delete the created run task settings and ensure we can ignore it if we no longer need to manage it
210+
PreConfig: delete_task_settings,
211+
Config: org_tf,
212+
Check: resource.ComposeTestCheckFunc(
213+
testCheckResourceNotExist("tfe_organization_run_task_global_settings.sut"),
214+
),
215+
},
216+
},
217+
})
218+
}
219+
148220
func testAccCheckTFEOrganizationRunTaskGlobalEnabled(resourceName string, expectedEnabled bool) resource.TestCheckFunc {
149221
return func(s *terraform.State) error {
150222
config := testAccProvider.Meta().(ConfiguredClient)

internal/provider/resource_tfe_organization_run_task_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,72 @@ func TestAccTFEOrganizationRunTask_import(t *testing.T) {
118118
})
119119
}
120120

121+
func TestAccTFEOrganizationRunTask_Read(t *testing.T) {
122+
skipUnlessRunTasksDefined(t)
123+
124+
tfeClient, err := getClientUsingEnv()
125+
if err != nil {
126+
t.Fatal(err)
127+
}
128+
129+
org, orgCleanup := createBusinessOrganization(t, tfeClient)
130+
t.Cleanup(orgCleanup)
131+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
132+
hmacKey := runTasksHMACKey()
133+
134+
org_tf := fmt.Sprintf(`data "tfe_organization" "orgtask" { name = %q }`, org.Name)
135+
136+
create_task_tf := fmt.Sprintf(`
137+
%s
138+
%s
139+
`, org_tf, testAccTFEOrganizationRunTask_basic(org.Name, rInt, runTasksURL(), hmacKey))
140+
141+
delete_tasks := func() {
142+
tasks, err := tfeClient.RunTasks.List(ctx, org.Name, nil)
143+
if err != nil || tasks == nil {
144+
t.Fatalf("Error listing tasks: %s", err)
145+
return
146+
}
147+
// There shouldn't be more that 25 run tasks so we don't need to worry about pagination
148+
for _, task := range tasks.Items {
149+
if task != nil {
150+
if err := tfeClient.RunTasks.Delete(ctx, task.ID); err != nil {
151+
t.Fatalf("Error deleting task: %s", err)
152+
}
153+
}
154+
}
155+
}
156+
157+
resource.Test(t, resource.TestCase{
158+
PreCheck: func() { testAccPreCheck(t) },
159+
ProtoV5ProviderFactories: testAccMuxedProviders,
160+
Steps: []resource.TestStep{
161+
{
162+
Config: create_task_tf,
163+
Check: resource.ComposeTestCheckFunc(
164+
resource.TestCheckResourceAttr("tfe_organization_run_task.foobar", "name", fmt.Sprintf("foobar-task-%d", rInt)),
165+
),
166+
},
167+
{
168+
// Delete the created run task and ensure we can re-create it
169+
PreConfig: delete_tasks,
170+
Config: create_task_tf,
171+
Check: resource.ComposeTestCheckFunc(
172+
resource.TestCheckResourceAttr("tfe_organization_run_task.foobar", "name", fmt.Sprintf("foobar-task-%d", rInt)),
173+
),
174+
},
175+
{
176+
// Delete the created run task and ensure we can ignore it if we no longer need to manage it
177+
PreConfig: delete_tasks,
178+
Config: org_tf,
179+
Check: resource.ComposeTestCheckFunc(
180+
testAccCheckTFEOrganizationRunTaskDestroy,
181+
),
182+
},
183+
},
184+
})
185+
}
186+
121187
func testAccCheckTFEOrganizationRunTaskExists(n string, runTask *tfe.RunTask) resource.TestCheckFunc {
122188
return func(s *terraform.State) error {
123189
config := testAccProvider.Meta().(ConfiguredClient)

internal/provider/resource_tfe_workspace_run_task.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ func (r *resourceWorkspaceRunTask) Read(ctx context.Context, req resource.ReadRe
122122
tflog.Debug(ctx, "Reading workspace run task")
123123
wstask, err := r.config.Client.WorkspaceRunTasks.Read(ctx, workspaceID, wstaskID)
124124
if err != nil {
125-
resp.Diagnostics.AddError("Error reading Workspace Run Task", "Could not read Workspace Run Task, unexpected error: "+err.Error())
125+
if errors.Is(err, tfe.ErrResourceNotFound) {
126+
resp.State.RemoveResource(ctx)
127+
} else {
128+
resp.Diagnostics.AddError("Error reading Workspace Run Task", "Could not read Workspace Run Task, unexpected error: "+err.Error())
129+
}
126130
return
127131
}
128132

internal/provider/resource_tfe_workspace_run_task_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,84 @@ func TestAccTFEWorkspaceRunTask_import(t *testing.T) {
182182
})
183183
}
184184

185+
func TestAccTFEWorkspaceRunTask_Read(t *testing.T) {
186+
skipUnlessRunTasksDefined(t)
187+
188+
tfeClient, err := getClientUsingEnv()
189+
if err != nil {
190+
t.Fatal(err)
191+
}
192+
193+
// Create test fixtures
194+
org, orgCleanup := createBusinessOrganization(t, tfeClient)
195+
t.Cleanup(orgCleanup)
196+
ws := createTempWorkspace(t, tfeClient, org.Name)
197+
key := runTasksHMACKey()
198+
task := createRunTask(t, tfeClient, org.Name, tfe.RunTaskCreateOptions{
199+
Name: fmt.Sprintf("tst-task-%s", randomString(t)),
200+
URL: runTasksURL(),
201+
HMACKey: &key,
202+
})
203+
204+
org_tf := fmt.Sprintf(`data "tfe_organization" "orgtask" { name = %q }`, org.Name)
205+
206+
create_wstask_tf := fmt.Sprintf(`
207+
%s
208+
resource "tfe_workspace_run_task" "foobar" {
209+
workspace_id = %q
210+
task_id = %q
211+
enforcement_level = "advisory"
212+
stage = "post_plan"
213+
}
214+
`, org_tf, ws.ID, task.ID)
215+
216+
delete_wstasks := func() {
217+
wstasks, err := tfeClient.WorkspaceRunTasks.List(ctx, ws.ID, nil)
218+
if err != nil || wstasks == nil {
219+
t.Fatalf("Error listing tasks: %s", err)
220+
return
221+
}
222+
// There shouldn't be more that 25 run tasks so we don't need to worry about pagination
223+
for _, wstask := range wstasks.Items {
224+
if wstask != nil {
225+
if err := tfeClient.WorkspaceRunTasks.Delete(ctx, ws.ID, wstask.ID); err != nil {
226+
t.Fatalf("Error deleting workspace task: %s", err)
227+
}
228+
}
229+
}
230+
}
231+
232+
resource.Test(t, resource.TestCase{
233+
PreCheck: func() { testAccPreCheck(t) },
234+
ProtoV5ProviderFactories: testAccMuxedProviders,
235+
CheckDestroy: testAccCheckTFETeamAccessDestroy,
236+
Steps: []resource.TestStep{
237+
{
238+
Config: create_wstask_tf,
239+
Check: resource.ComposeTestCheckFunc(
240+
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "enforcement_level", "advisory"),
241+
),
242+
},
243+
{
244+
// Delete the created workspace run task and ensure we can re-create it
245+
PreConfig: delete_wstasks,
246+
Config: create_wstask_tf,
247+
Check: resource.ComposeTestCheckFunc(
248+
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "enforcement_level", "advisory"),
249+
),
250+
},
251+
{
252+
// Delete the created workspace run task and ensure we can ignore it if we no longer need to manage it
253+
PreConfig: delete_wstasks,
254+
Config: org_tf,
255+
Check: resource.ComposeTestCheckFunc(
256+
testAccCheckTFEWorkspaceRunTaskDestroy,
257+
),
258+
},
259+
},
260+
})
261+
}
262+
185263
func testAccCheckTFEWorkspaceRunTaskExists(n string, runTask *tfe.WorkspaceRunTask) resource.TestCheckFunc {
186264
return func(s *terraform.State) error {
187265
config := testAccProvider.Meta().(ConfiguredClient)

0 commit comments

Comments
 (0)