From 9148ced12b38023c806232fbc235b79b32239d4c Mon Sep 17 00:00:00 2001 From: 1riatsila1 Date: Thu, 10 Oct 2024 14:06:04 +0200 Subject: [PATCH] feat: neatening up error handling --- .../provider/resources/group.go | 56 ++++++++-------- .../resources/network_group_assignment.go | 55 +++++++++------- .../resources/sensor_group_assignment.go | 65 +++++++++---------- .../resources/service_group_assignment.go | 15 +++-- .../provider/resources/wired_network.go | 20 ++++-- .../provider/resources/wireless_network.go | 20 ++++-- .../provider/util/error_handling.go | 49 ++++++++++++++ .../test/resources/group_test.go | 2 +- 8 files changed, 176 insertions(+), 106 deletions(-) create mode 100644 pkg/config-api-provider/provider/util/error_handling.go diff --git a/pkg/config-api-provider/provider/resources/group.go b/pkg/config-api-provider/provider/resources/group.go index 635d05e6..601f9621 100644 --- a/pkg/config-api-provider/provider/resources/group.go +++ b/pkg/config-api-provider/provider/resources/group.go @@ -26,13 +26,6 @@ type groupResourceModel struct { ParentGroupId types.String `tfsdk:"parent_group_id"` } -// TODO: Remove this once we rely fully on client for groups - -// TODO: Remove this once we rely fully on client for groups -type GroupUpdateRequestModel struct { - Name string -} - func NewGroupResource() resource.Resource { return &groupResource{} } @@ -99,12 +92,14 @@ func (r *groupResource) Create(ctx context.Context, req resource.CreateRequest, groups_post_request := config_api_client.NewGroupsPostRequest(plan.ParentGroupId.ValueString(), plan.Name.ValueString()) request := r.client.ConfigurationAPI.GroupsPostUxiV1alpha1GroupsPost(ctx).GroupsPostRequest(*groups_post_request) - group, _, err := util.RetryFor429(request.Execute) - if err != nil { - resp.Diagnostics.AddError( - "Error creating group", - "Could not create group, unexpected error: "+err.Error(), - ) + group, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("create", "uxi_group"), errorDetail) return } @@ -133,20 +128,27 @@ func (r *groupResource) Read(ctx context.Context, req resource.ReadRequest, resp request := r.client.ConfigurationAPI. GroupsGetUxiV1alpha1GroupsGet(ctx). Uid(state.ID.ValueString()) + groupResponse, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() - groupResponse, _, err := util.RetryFor429(request.Execute) + errorSummary := util.GenerateErrorSummary("read", "uxi_group") - if err != nil || len(groupResponse.Items) != 1 { - resp.Diagnostics.AddError( - "Error reading Group", - "Could not retrieve Group, unexpected error: "+err.Error(), - ) + if errorPresent { + resp.Diagnostics.AddError(errorSummary, errorDetail) + return + } + + if len(groupResponse.Items) != 1 { + resp.Diagnostics.AddError(errorSummary, "Could not find specified resource") return } group := groupResponse.Items[0] if util.IsRoot(group) { - resp.Diagnostics.AddError("operation not supported", "the root group cannot be used as a resource") + resp.Diagnostics.AddError(errorSummary, "The root group cannot be used as a resource") return } @@ -175,13 +177,15 @@ func (r *groupResource) Update(ctx context.Context, req resource.UpdateRequest, request := r.client.ConfigurationAPI. GroupsPatchUxiV1alpha1GroupsGroupUidPatch(ctx, plan.ID.ValueString()). GroupsPatchRequest(*patchRequest) - group, _, err := util.RetryFor429(request.Execute) + group, response, err := util.RetryFor429(request.Execute) - if err != nil { - resp.Diagnostics.AddError( - "Error updating Group", - "Could not update Group, unexpected error: "+err.Error(), - ) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("update", "uxi_group"), errorDetail) return } diff --git a/pkg/config-api-provider/provider/resources/network_group_assignment.go b/pkg/config-api-provider/provider/resources/network_group_assignment.go index 589261f8..26d1ed53 100644 --- a/pkg/config-api-provider/provider/resources/network_group_assignment.go +++ b/pkg/config-api-provider/provider/resources/network_group_assignment.go @@ -25,12 +25,6 @@ type networkGroupAssignmentResourceModel struct { GroupID types.String `tfsdk:"group_id"` } -type NetworkGroupAssignmentResponseModel struct { - UID string // - GroupUID string // , - NetworkUID string // -} - func NewNetworkGroupAssignmentResource() resource.Resource { return &networkGroupAssignmentResource{} } @@ -102,12 +96,14 @@ func (r *networkGroupAssignmentResource) Create(ctx context.Context, req resourc request := r.client.ConfigurationAPI. PostUxiV1alpha1NetworkGroupAssignmentsPost(ctx). NetworkGroupAssignmentsPostRequest(*postRequest) - networkGroupAssignment, _, err := util.RetryFor429(request.Execute) - if err != nil { - resp.Diagnostics.AddError( - "Error updating Network Group Assignment", - "Could not update Network Group Assignment, unexpected error: "+err.Error(), - ) + networkGroupAssignment, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("create", "uxi_network_group_assignment"), errorDetail) return } @@ -136,13 +132,21 @@ func (r *networkGroupAssignmentResource) Read(ctx context.Context, req resource. request := r.client.ConfigurationAPI. GetUxiV1alpha1NetworkGroupAssignmentsGet(ctx). Uid(state.ID.ValueString()) - networkGroupAssignmentResponse, _, err := util.RetryFor429(request.Execute) + networkGroupAssignmentResponse, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() - if err != nil || len(networkGroupAssignmentResponse.Items) != 1 { - resp.Diagnostics.AddError( - "Error reading Network Group Assignment", - "Could not retrieve Network Group Assignment, unexpected error: "+err.Error(), - ) + errorSummary := util.GenerateErrorSummary("read", "uxi_network_group_assignment") + + if errorPresent { + resp.Diagnostics.AddError(errorSummary, errorDetail) + return + } + + if len(networkGroupAssignmentResponse.Items) != 1 { + resp.Diagnostics.AddError(errorSummary, "Could not find specified resource") return } networkGroupAssignment := networkGroupAssignmentResponse.Items[0] @@ -181,13 +185,14 @@ func (r *networkGroupAssignmentResource) Delete(ctx context.Context, req resourc request := r.client.ConfigurationAPI. DeleteNetworkGroupAssignmentUxiV1alpha1NetworkGroupAssignmentsIdDelete(ctx, state.ID.ValueString()) - _, _, err := util.RetryFor429(request.Execute) - - if err != nil { - resp.Diagnostics.AddError( - "Error deleting Network Group Assignment", - "Could not delete Network Group Assignment, unexpected error: "+err.Error(), - ) + _, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("delete", "uxi_network_group_assignment"), errorDetail) return } } diff --git a/pkg/config-api-provider/provider/resources/sensor_group_assignment.go b/pkg/config-api-provider/provider/resources/sensor_group_assignment.go index e47fcdb0..6ce72dab 100644 --- a/pkg/config-api-provider/provider/resources/sensor_group_assignment.go +++ b/pkg/config-api-provider/provider/resources/sensor_group_assignment.go @@ -25,12 +25,6 @@ type sensorGroupAssignmentResourceModel struct { GroupID types.String `tfsdk:"group_id"` } -type SensorGroupAssignmentResponseModel struct { - UID string `json:"uid"` - GroupUID string `json:"group_uid"` - SensorUID string `json:"sensor_uid"` -} - type SensorGroupAssignmentRequestModel struct { GroupUID string // , SensorUID string // @@ -105,12 +99,14 @@ func (r *sensorGroupAssignmentResource) Create(ctx context.Context, req resource postRequest := config_api_client.NewSensorGroupAssignmentsPostRequest(plan.GroupID.ValueString(), plan.SensorID.ValueString()) request := r.client.ConfigurationAPI.PostUxiV1alpha1SensorGroupAssignmentsPost(ctx).SensorGroupAssignmentsPostRequest(*postRequest) - sensorGroupAssignment, _, err := util.RetryFor429(request.Execute) - if err != nil { - resp.Diagnostics.AddError( - "Error creating sensor group assignment", - "Could not create sensor group assignment, unexpected error: "+err.Error(), - ) + sensorGroupAssignment, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("create", "uxi_sensor_group_assignment"), errorDetail) return } @@ -137,13 +133,21 @@ func (r *sensorGroupAssignmentResource) Read(ctx context.Context, req resource.R request := r.client.ConfigurationAPI. GetUxiV1alpha1SensorGroupAssignmentsGet(ctx). Uid(state.ID.ValueString()) - sensorGroupAssignmentResponse, _, err := util.RetryFor429(request.Execute) + sensorGroupAssignmentResponse, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() - if err != nil || len(sensorGroupAssignmentResponse.Items) != 1 { - resp.Diagnostics.AddError( - "Error reading Sensor Group Assignment", - "Could not retrieve Sensor Group Assignment, unexpected error: "+err.Error(), - ) + errorSummary := util.GenerateErrorSummary("create", "uxi_sensor_group_assignment") + + if errorPresent { + resp.Diagnostics.AddError(errorSummary, errorDetail) + return + } + + if len(sensorGroupAssignmentResponse.Items) != 1 { + resp.Diagnostics.AddError(errorSummary, "Could not find specified resource") return } @@ -184,13 +188,14 @@ func (r *sensorGroupAssignmentResource) Delete(ctx context.Context, req resource // Delete existing sensorGroupAssignment using the plan_id request := r.client.ConfigurationAPI. DeleteSensorGroupAssignmentUxiV1alpha1SensorGroupAssignmentsIdDelete(ctx, state.ID.ValueString()) - _, _, err := util.RetryFor429(request.Execute) - - if err != nil { - resp.Diagnostics.AddError( - "Error deleting Sensor Group Assignment", - "Could not deleting Sensor Group Assignment, unexpected error: "+err.Error(), - ) + _, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("delete", "uxi_sensor_group_assignment"), errorDetail) return } } @@ -198,13 +203,3 @@ func (r *sensorGroupAssignmentResource) Delete(ctx context.Context, req resource func (r *sensorGroupAssignmentResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } - -var CreateSensorGroupAssignment = func(request SensorGroupAssignmentRequestModel) SensorGroupAssignmentResponseModel { - // TODO: Query the sensorGroupAssignment using the client - - return SensorGroupAssignmentResponseModel{ - UID: "mock_uid", - GroupUID: "mock_group_uid", - SensorUID: "mock_sensor_uid", - } -} diff --git a/pkg/config-api-provider/provider/resources/service_group_assignment.go b/pkg/config-api-provider/provider/resources/service_group_assignment.go index e2b91694..8d03e770 100644 --- a/pkg/config-api-provider/provider/resources/service_group_assignment.go +++ b/pkg/config-api-provider/provider/resources/service_group_assignment.go @@ -96,13 +96,14 @@ func (r *serviceTestGroupAssignmentResource) Create(ctx context.Context, req res request := r.client.ConfigurationAPI. PostUxiV1alpha1ServiceTestGroupAssignmentsPost(ctx). ServiceTestGroupAssignmentsPostRequest(*postRequest) - serviceTestGroupAssignment, _, err := util.RetryFor429(request.Execute) - - if err != nil { - resp.Diagnostics.AddError( - "Error creating Service Test Group Assignment", - "Could not create Network Group Assignment, unexpected error: "+err.Error(), - ) + serviceTestGroupAssignment, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() + + if errorPresent { + resp.Diagnostics.AddError(util.GenerateErrorSummary("delete", "uxi_service_test_group_assignment"), errorDetail) return } diff --git a/pkg/config-api-provider/provider/resources/wired_network.go b/pkg/config-api-provider/provider/resources/wired_network.go index 19e4d41e..ca35e348 100644 --- a/pkg/config-api-provider/provider/resources/wired_network.go +++ b/pkg/config-api-provider/provider/resources/wired_network.go @@ -92,13 +92,21 @@ func (r *wiredNetworkResource) Read(ctx context.Context, req resource.ReadReques request := r.client.ConfigurationAPI. GetUxiV1alpha1WiredNetworksGet(ctx). Uid(state.ID.ValueString()) - networkResponse, _, err := util.RetryFor429(request.Execute) + networkResponse, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() - if err != nil || len(networkResponse.Items) != 1 { - resp.Diagnostics.AddError( - "Error reading Wired Network", - "Could not retrieve Wired Network, unexpected error: "+err.Error(), - ) + errorSummary := util.GenerateErrorSummary("read", "uxi_wired_network") + + if errorPresent { + resp.Diagnostics.AddError(errorSummary, errorDetail) + return + } + + if len(networkResponse.Items) != 1 { + resp.Diagnostics.AddError(errorSummary, "Could not find specified resource") return } diff --git a/pkg/config-api-provider/provider/resources/wireless_network.go b/pkg/config-api-provider/provider/resources/wireless_network.go index 8de52291..46c078bf 100644 --- a/pkg/config-api-provider/provider/resources/wireless_network.go +++ b/pkg/config-api-provider/provider/resources/wireless_network.go @@ -92,13 +92,21 @@ func (r *wirelessNetworkResource) Read(ctx context.Context, req resource.ReadReq request := r.client.ConfigurationAPI. GetUxiV1alpha1WirelessNetworksGet(ctx). Uid(state.ID.ValueString()) - networkResponse, _, err := util.RetryFor429(request.Execute) + networkResponse, response, err := util.RetryFor429(request.Execute) + errorPresent, errorDetail := util.ResponseStatusCheck{ + Response: response, + Err: err, + }.RaiseForStatus() - if err != nil || len(networkResponse.Items) != 1 { - resp.Diagnostics.AddError( - "Error reading Wireless Networks", - "Could not retrieve Wireless Network, unexpected error: "+err.Error(), - ) + errorSummary := util.GenerateErrorSummary("read", "uxi_wireless_network") + + if errorPresent { + resp.Diagnostics.AddError(errorSummary, errorDetail) + return + } + + if len(networkResponse.Items) != 1 { + resp.Diagnostics.AddError(errorSummary, "Could not find specified resource") return } diff --git a/pkg/config-api-provider/provider/util/error_handling.go b/pkg/config-api-provider/provider/util/error_handling.go new file mode 100644 index 00000000..6ef1c319 --- /dev/null +++ b/pkg/config-api-provider/provider/util/error_handling.go @@ -0,0 +1,49 @@ +package util + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" +) + +func GenerateErrorSummary(actionName string, entityName string) string { + return fmt.Sprintf("Error performing %s on %s", actionName, entityName) +} + +type ResponseStatusCheck struct { + Response *http.Response + Err error +} + +func (r ResponseStatusCheck) RaiseForStatus() (bool, string) { + if r.Err != nil { + var detail string + var data map[string]interface{} + + switch e := r.Err.(type) { + case *url.Error: + detail = r.handleURLError(e) + default: + err := json.NewDecoder(r.Response.Body).Decode(&data) + if err != nil { + detail = "Unexpected error: " + r.Err.Error() + } else { + detail = data["message"].(string) + "\nDebugID: " + data["debugId"].(string) + } + } + + return true, detail + } + return false, "" +} + +func (r ResponseStatusCheck) handleURLError(uErr *url.Error) string { + if uErr.Timeout() { + return "Error: Request timed out. Please check your network." + } else if uErr.Temporary() { + return "Error: Temporary network error. Please try again later." + } else { + return fmt.Sprintf("URL Error: %v\n", uErr) + } +} diff --git a/pkg/config-api-provider/test/resources/group_test.go b/pkg/config-api-provider/test/resources/group_test.go index 2db55206..be620f37 100644 --- a/pkg/config-api-provider/test/resources/group_test.go +++ b/pkg/config-api-provider/test/resources/group_test.go @@ -149,7 +149,7 @@ func TestRootGroupResource(t *testing.T) { to = uxi_group.my_root_group id = "my_root_group_uid" }`, - ExpectError: regexp.MustCompile(`the root group cannot be used as a resource`), + ExpectError: regexp.MustCompile(`The root group cannot be used as a resource`), }, }, })