Skip to content

Commit

Permalink
Merge pull request #5 from ambarltd/ResourceNotFound
Browse files Browse the repository at this point in the history
Handle ResourceNotFound errors gracefully on Read and Delete
  • Loading branch information
tjschutte authored Feb 7, 2024
2 parents da04fa4 + 8f741f3 commit 7188f5b
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ website/node_modules
*.iml
*.test
*.iml
*.info

website/vendor

Expand Down
57 changes: 51 additions & 6 deletions internal/provider/data_destination_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"net/http"
"strconv"
"time"
)

Expand Down Expand Up @@ -174,6 +177,7 @@ func (r *DataDestinationResource) Create(ctx context.Context, req resource.Creat

describeResourceResponse, _, err = r.client.AmbarAPI.DescribeDataDestination(ctx).DescribeResourceRequest(describeDataDestination).Execute()
if err != nil {
tflog.Debug(ctx, "Got error while waiting for resource to become ready: "+err.Error())
return
}

Expand Down Expand Up @@ -205,9 +209,27 @@ func (r *DataDestinationResource) Read(ctx context.Context, req resource.ReadReq
var describeDataDestination Ambar.DescribeResourceRequest
describeDataDestination.ResourceId = data.ResourceId.ValueString()

describeResourceResponse, _, err := r.client.AmbarAPI.DescribeDataDestination(ctx).DescribeResourceRequest(describeDataDestination).Execute()
// Todo: Handle ResourceNotFoundException gracefully per https://developer.hashicorp.com/terraform/plugin/framework/resources/read#recommendations
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeDataDestination(ctx).DescribeResourceRequest(describeDataDestination).Execute()
if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataSource resource.", err.Error())
return
}

tflog.Debug(ctx, "Got state: "+describeResourceResponse.State)
// If the resource is in the deleting state, then we should consider it deleted.
if describeResourceResponse.State == "DELETING" {
tflog.Info(ctx, "Resource was found in DELETING state and will not exist eventually. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

Expand Down Expand Up @@ -291,23 +313,46 @@ func (r *DataDestinationResource) Delete(ctx context.Context, req resource.Delet
var deleteDataDestination Ambar.DeleteResourceRequest
deleteDataDestination.ResourceId = data.ResourceId.ValueString()

_, _, err := r.client.AmbarAPI.DeleteDataDestination(ctx).DeleteResourceRequest(deleteDataDestination).Execute()
// Todo: Error handling as this call should not throw
deleteResponse, httpResponse, err := r.client.AmbarAPI.DeleteDataDestination(ctx).DeleteResourceRequest(deleteDataDestination).Execute()
if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to delete DataDestination resource.", err.Error())
return
}
tflog.Info(ctx, "Got deleteResponse: "+deleteResponse.State)

// Wait for confirmation the resource is Deleted via a ResourceNotFound error when describing it.
var describeDataDestination Ambar.DescribeResourceRequest
describeDataDestination.ResourceId = data.ResourceId.ValueString()

for {
time.Sleep(10 * time.Second)

_, _, err := r.client.AmbarAPI.DescribeDataDestination(ctx).DescribeResourceRequest(describeDataDestination).Execute()
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeDataDestination(ctx).DescribeResourceRequest(describeDataDestination).Execute()

if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. This is expected for delete, returning.")
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataDestination resource to confirm deletion. Got error.", err.Error())
return
}

tflog.Debug(ctx, "Waiting for resource to complete deletion. Current state: "+describeResourceResponse.State)
}
}

Expand Down
62 changes: 51 additions & 11 deletions internal/provider/data_source_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"net/http"
"strconv"
"strings"
"time"
)
Expand Down Expand Up @@ -195,11 +197,28 @@ func (r *dataSourceResource) Read(ctx context.Context, req resource.ReadRequest,
var describeDataSource Ambar.DescribeResourceRequest
describeDataSource.ResourceId = data.ResourceId.ValueString()

describeResourceResponse, _, err := r.client.AmbarAPI.DescribeDataSource(ctx).DescribeResourceRequest(describeDataSource).Execute()
tflog.Debug(ctx, "Got state: "+describeResourceResponse.State)
// Todo: Handle ResourceNotFoundException gracefully per https://developer.hashicorp.com/terraform/plugin/framework/resources/read#recommendations
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeDataSource(ctx).DescribeResourceRequest(describeDataSource).Execute()

if err != nil {
tflog.Error(ctx, "Got error!"+err.Error())
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataSource resource.", err.Error())
return
}

tflog.Debug(ctx, "Got state: "+describeResourceResponse.State)
// If the resource is in the deleting state, then we should consider it deleted.
if describeResourceResponse.State == "DELETING" {
tflog.Info(ctx, "Resource was found in DELETING state and will not exist eventually. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

Expand Down Expand Up @@ -243,27 +262,48 @@ func (r *dataSourceResource) Delete(ctx context.Context, req resource.DeleteRequ
var deleteDataSource Ambar.DeleteResourceRequest
deleteDataSource.ResourceId = data.ResourceId.ValueString()

deleteResponse, _, err := r.client.AmbarAPI.DeleteDataSource(ctx).DeleteResourceRequest(deleteDataSource).Execute()
tflog.Debug(ctx, "Got state: "+deleteResponse.State)
deleteResponse, httpResponse, err := r.client.AmbarAPI.DeleteDataSource(ctx).DeleteResourceRequest(deleteDataSource).Execute()
if err != nil {
tflog.Error(ctx, "Got error!"+err.Error())
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to delete DataSource resource.", err.Error())
return
}
tflog.Info(ctx, "Got deleteResponse: "+deleteResponse.State)

// Wait for confirmation the resource is Deleted via a ResourceNotFound error when describing it.
var describeDataSource Ambar.DescribeResourceRequest
describeDataSource.ResourceId = data.ResourceId.ValueString()

for {
time.Sleep(10 * time.Second)

describeResourceResponse, _, err := r.client.AmbarAPI.DescribeDataSource(ctx).DescribeResourceRequest(describeDataSource).Execute()
tflog.Debug(ctx, "Got state: "+describeResourceResponse.State)
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeDataSource(ctx).DescribeResourceRequest(describeDataSource).Execute()

if err != nil {
tflog.Error(ctx, "Got error!"+err.Error())
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. This is expected for delete, returning.")
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataSource resource to confirm deletion. Got error.", err.Error())
return
}

tflog.Debug(ctx, "Waiting for resource to complete deletion. Current state: "+describeResourceResponse.State)
}

}

func (r *dataSourceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
Expand Down
61 changes: 53 additions & 8 deletions internal/provider/filter_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"net/http"
"strconv"
"time"
)

Expand Down Expand Up @@ -136,15 +139,16 @@ func (r *FilterResource) Create(ctx context.Context, req resource.CreateRequest,
return
}

// Give a few seconds for eventual consistency / resource to finish creating.
time.Sleep(5 * time.Second)

var describeFilter Ambar.DescribeResourceRequest
describeFilter.ResourceId = createResourceResponse.ResourceId

describeResourceResponse, _, err := r.client.AmbarAPI.DescribeFilter(ctx).DescribeResourceRequest(describeFilter).Execute()

if err != nil {
resp.Diagnostics.AddWarning("Help", "me")
resp.Diagnostics.AddWarning("Help", err.Error())
resp.Diagnostics.AddError("Error while describing Filter resource", err.Error())
return
}

Expand Down Expand Up @@ -174,9 +178,27 @@ func (r *FilterResource) Read(ctx context.Context, req resource.ReadRequest, res
var describeFilter Ambar.DescribeResourceRequest
describeFilter.ResourceId = data.ResourceId.ValueString()

describeResourceResponse, _, err := r.client.AmbarAPI.DescribeFilter(ctx).DescribeResourceRequest(describeFilter).Execute()
// Todo: Handle ResourceNotFoundException gracefully per https://developer.hashicorp.com/terraform/plugin/framework/resources/read#recommendations
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeFilter(ctx).DescribeResourceRequest(describeFilter).Execute()
if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataSource resource.", err.Error())
return
}

tflog.Debug(ctx, "Got state: "+describeResourceResponse.State)
// If the resource is in the deleting state, then we should consider it deleted.
if describeResourceResponse.State == "DELETING" {
tflog.Info(ctx, "Resource was found in DELETING state and will not exist eventually. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

Expand Down Expand Up @@ -219,23 +241,46 @@ func (r *FilterResource) Delete(ctx context.Context, req resource.DeleteRequest,
var deleteFilter Ambar.DeleteResourceRequest
deleteFilter.ResourceId = data.ResourceId.ValueString()

_, _, err := r.client.AmbarAPI.DeleteFilter(ctx).DeleteResourceRequest(deleteFilter).Execute()
// Todo: Error handling as this call should not throw
deleteResponse, httpResponse, err := r.client.AmbarAPI.DeleteFilter(ctx).DeleteResourceRequest(deleteFilter).Execute()
if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. Removing from state.")
resp.State.RemoveResource(ctx)
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to delete DataDestination resource.", err.Error())
return
}
tflog.Info(ctx, "Got deleteResponse: "+deleteResponse.State)

// Wait for confirmation the resource is Deleted via a ResourceNotFound error when describing it.
var describeFilter Ambar.DescribeResourceRequest
describeFilter.ResourceId = data.ResourceId.ValueString()

for {
time.Sleep(10 * time.Second)

_, _, err := r.client.AmbarAPI.DescribeFilter(ctx).DescribeResourceRequest(describeFilter).Execute()
describeResourceResponse, httpResponse, err := r.client.AmbarAPI.DescribeDataSource(ctx).DescribeResourceRequest(describeFilter).Execute()

if err != nil {
tflog.Error(ctx, "Got error: "+err.Error())

if httpResponse.StatusCode == http.StatusNotFound {
tflog.Info(ctx, "Resource was not found. This is expected for delete, returning.")
return
}

tflog.Error(ctx, "Unexpected error, dumping logs and returning.")
tflog.Error(ctx, "Got http response, code: "+strconv.Itoa(httpResponse.StatusCode)+", status: "+httpResponse.Status)
resp.Diagnostics.AddError("Unable to read DataDestination resource to confirm deletion. Got error.", err.Error())
return
}

tflog.Debug(ctx, "Waiting for resource to complete deletion. Current state: "+describeResourceResponse.State)
}
}

Expand Down

0 comments on commit 7188f5b

Please sign in to comment.