Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions stackit/internal/services/sfs/export-policy/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func (r *exportPolicyResource) Create(ctx context.Context, req resource.CreateRe

createResp, err := r.client.CreateShareExportPolicy(ctx, projectId, region).CreateShareExportPolicyPayload(*payload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating export policy", fmt.Sprintf("Calling API: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error creating export policy", "Calling API", err)
return
}

Expand Down Expand Up @@ -402,7 +402,7 @@ func (r *exportPolicyResource) Update(ctx context.Context, req resource.UpdateRe

_, err = r.client.UpdateShareExportPolicy(ctx, projectId, region, exportPolicyId).UpdateShareExportPolicyPayload(*payload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating export policy", fmt.Sprintf("Calling API to update export policy: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error updating export policy", "Calling API to update export policy", err)
return
}

Expand Down
4 changes: 2 additions & 2 deletions stackit/internal/services/sfs/resourcepool/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func (r *resourcePoolResource) Create(ctx context.Context, req resource.CreateRe
CreateResourcePoolPayload(*payload).
Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating resource pool", fmt.Sprintf("Calling API: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error creating resource pool", "Calling API", err)
return
}

Expand Down Expand Up @@ -380,7 +380,7 @@ func (r *resourcePoolResource) Update(ctx context.Context, req resource.UpdateRe
return
}
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating resource pool", fmt.Sprintf("Calling API: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error updating resource pool", "Calling API", err)
return
}

Expand Down
45 changes: 45 additions & 0 deletions stackit/internal/services/sfs/sfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,48 @@ resource "stackit_sfs_share" "example" {
},
})
}

func TestLogAndErrorPrintsValidationMessage(t *testing.T) {
projectId := uuid.NewString()
const region = "eu01"
s := testutil.NewMockServer(t)
defer s.Server.Close()
tfConfig := fmt.Sprintf(`
provider "stackit" {
default_region = "%s"
sfs_custom_endpoint = "%s"
service_account_token = "mock-server-needs-no-auth"
enable_beta_resources = true
}
resource "stackit_sfs_resource_pool" "resourcepool" {
project_id = "%s"
name = "sfs-instance"
availability_zone = "eu01-m"
performance_class = "Standard"
size_gigabytes = 512
ip_acl = ["192.168.2.0/24"]
}
`, region, s.Server.URL, projectId)
s.Reset(testutil.MockResponse{
StatusCode: http.StatusBadRequest,
ToJsonBody: sfs.ValidationError{
Type: utils.Ptr("storage.stackit.cloud/validation-error"),
Title: utils.Ptr("Validation Failed"),
Fields: &[]sfs.ValidationErrorField{
{
Field: utils.Ptr("ip"),
Reason: utils.Ptr("999.999.999 is not a valid ip address"),
},
},
},
})
resource.UnitTest(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: tfConfig,
ExpectError: regexp.MustCompile(".*Calling API: Validation Failed\n\nField: ip \\| Reason: 999.999.999 is not a valid ip address"),
},
},
})
}
4 changes: 2 additions & 2 deletions stackit/internal/services/sfs/share/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (r *shareResource) Create(ctx context.Context, req resource.CreateRequest,
CreateSharePayload(payload).
Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating share", fmt.Sprintf("Calling API: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error creating share", "Calling API", err)
return
}

Expand Down Expand Up @@ -382,7 +382,7 @@ func (r *shareResource) Update(ctx context.Context, req resource.UpdateRequest,
return
}
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating share", fmt.Sprintf("Calling API: %v", err))
sfsUtils.LogAndAddError(ctx, &resp.Diagnostics, "Error updating share", "Calling API", err)
return
}

Expand Down
40 changes: 40 additions & 0 deletions stackit/internal/services/sfs/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package utils

import (
"context"
"errors"
"fmt"
"strings"

"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/sfs"

"github.com/hashicorp/terraform-plugin-framework/diag"
Expand All @@ -28,3 +31,40 @@ func ConfigureClient(ctx context.Context, providerData *core.ProviderData, diags

return apiClient
}

func DescribeValidationError(err sfs.ValidationError) string {
var sb strings.Builder
if err.Title != nil {
sb.WriteString(*err.Title)
sb.WriteRune('\n')
}
if fields := err.Fields; fields != nil {
for _, field := range *fields {
sb.WriteRune('\n')
sb.WriteString("Field: ")
if field.Field != nil {
sb.WriteString(*field.Field)
}
sb.WriteString(" | Reason: ")
if field.Reason != nil {
sb.WriteString(*field.Reason)
}
}
}
return sb.String()
}

func LogAndAddError(ctx context.Context, diags *diag.Diagnostics, summary, detail string, err error) {
if err == nil {
return
}
message := err.Error()
var oapiErr *oapierror.GenericOpenAPIError
if errors.As(err, &oapiErr) {
errModel := oapiErr.Model
if validationErr, ok := errModel.(sfs.ValidationError); ok {
message = DescribeValidationError(validationErr)
}
}
core.LogAndAddError(ctx, diags, summary, fmt.Sprintf("%s: %v", detail, message))
}
49 changes: 49 additions & 0 deletions stackit/internal/services/sfs/utils/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"reflect"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/diag"
sdkClients "github.com/stackitcloud/stackit-sdk-go/core/clients"
"github.com/stackitcloud/stackit-sdk-go/core/config"
utils2 "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/sfs"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
Expand Down Expand Up @@ -91,3 +93,50 @@ func TestConfigureClient(t *testing.T) {
})
}
}

func TestDescribeValidationError(t *testing.T) {
tests := []struct {
name string
err sfs.ValidationError
want string
}{
{
name: "just title",
err: sfs.ValidationError{
Title: utils2.Ptr("nice title"),
},
want: `nice title
`,
},
{
name: "with fields",
err: sfs.ValidationError{
Title: utils2.Ptr("nice title"),
Fields: &[]sfs.ValidationErrorField{
{
Field: utils2.Ptr("field-a"),
Reason: utils2.Ptr("reason-a"),
},
{
Reason: utils2.Ptr("reason-b"),
},
{
Field: utils2.Ptr("field-c"),
},
},
},
want: `nice title

Field: field-a | Reason: reason-a
Field: | Reason: reason-b
Field: field-c | Reason: `,
},
}

for _, tt := range tests {
got := DescribeValidationError(tt.err)
if d := cmp.Diff(got, tt.want); d != "" {
t.Errorf("DescribeValidationError() = got diff: %s", d)
}
}
}
9 changes: 5 additions & 4 deletions stackit/internal/testutil/mockserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,19 @@ func (m *MockServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
next.Handler(w, r)
return
}
status := next.StatusCode
if status == 0 {
status = http.StatusOK
}
if next.ToJsonBody != nil {
bs, err := json.Marshal(next.ToJsonBody)
if err != nil {
m.t.Fatalf("Error marshaling response body: %v", err)
}
w.Header().Set("content-type", "application/json")
w.WriteHeader(status)
w.Write(bs) //nolint:errcheck //test will fail when this happens
}
status := next.StatusCode
if status == 0 {
status = http.StatusOK
}
w.WriteHeader(status)
}

Expand Down
Loading