Skip to content

Commit

Permalink
Merge branch 'master' into feat/add-validation-domain-ressource
Browse files Browse the repository at this point in the history
  • Loading branch information
jremy42 committed Mar 13, 2024
2 parents a932e19 + 5b864a6 commit 4296f06
Show file tree
Hide file tree
Showing 238 changed files with 1,010 additions and 703 deletions.
50 changes: 50 additions & 0 deletions internal/httperrors/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package httperrors

import (
"errors"
"net/http"

"github.com/scaleway/scaleway-sdk-go/scw"
)

// IsHTTPCodeError returns true if err is an http error with code statusCode
func IsHTTPCodeError(err error, statusCode int) bool {
if err == nil {
return false
}

responseError := &scw.ResponseError{}
if errors.As(err, &responseError) && responseError.StatusCode == statusCode {
return true
}
return false
}

// Is404 returns true if err is an HTTP 404 error
func Is404(err error) bool {
notFoundError := &scw.ResourceNotFoundError{}
return IsHTTPCodeError(err, http.StatusNotFound) || errors.As(err, &notFoundError)
}

func Is412(err error) bool {
preConditionFailedError := &scw.PreconditionFailedError{}
return IsHTTPCodeError(err, http.StatusPreconditionFailed) || errors.As(err, &preConditionFailedError)
}

// Is403 returns true if err is an HTTP 403 error
func Is403(err error) bool {
permissionsDeniedError := &scw.PermissionsDeniedError{}
return IsHTTPCodeError(err, http.StatusForbidden) || errors.As(err, &permissionsDeniedError)
}

// Is409 return true is err is an HTTP 409 error
func Is409(err error) bool {
// check transient error
transientStateError := &scw.TransientStateError{}
return IsHTTPCodeError(err, http.StatusConflict) || errors.As(err, &transientStateError)
}

// Is410 returns true if err is an HTTP 410 error
func Is410(err error) bool {
return IsHTTPCodeError(err, http.StatusGone)
}
30 changes: 30 additions & 0 deletions internal/httperrors/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package httperrors_test

import (
"errors"
"net/http"
"testing"

"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/stretchr/testify/assert"
)

func TestIsHTTPCodeError(t *testing.T) {
assert.True(t, httperrors.IsHTTPCodeError(&scw.ResponseError{StatusCode: http.StatusBadRequest}, http.StatusBadRequest))
assert.False(t, httperrors.IsHTTPCodeError(nil, http.StatusBadRequest))
assert.False(t, httperrors.IsHTTPCodeError(&scw.ResponseError{StatusCode: http.StatusBadRequest}, http.StatusNotFound))
assert.False(t, httperrors.IsHTTPCodeError(errors.New("not an http error"), http.StatusNotFound))
}

func TestIs404Error(t *testing.T) {
assert.True(t, httperrors.Is404(&scw.ResponseError{StatusCode: http.StatusNotFound}))
assert.False(t, httperrors.Is404(nil))
assert.False(t, httperrors.Is404(&scw.ResponseError{StatusCode: http.StatusBadRequest}))
}

func TestIs403Error(t *testing.T) {
assert.True(t, httperrors.Is403(&scw.ResponseError{StatusCode: http.StatusForbidden}))
assert.False(t, httperrors.Is403(nil))
assert.False(t, httperrors.Is403(&scw.ResponseError{StatusCode: http.StatusBadRequest}))
}
23 changes: 23 additions & 0 deletions internal/verify/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package verify

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/scaleway/scaleway-sdk-go/validation"
)

func IsEmail() schema.SchemaValidateFunc {
return func(v interface{}, key string) (warnings []string, errors []error) {
email, isString := v.(string)
if !isString {
return nil, []error{fmt.Errorf("invalid email for key '%s': not a string", key)}
}

if !validation.IsEmail(email) {
return nil, []error{fmt.Errorf("invalid email for key '%s': '%s': should contain valid '@' character", key, email)}
}

return
}
}
30 changes: 30 additions & 0 deletions internal/verify/ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package verify

import (
"fmt"
"net"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func IsStandaloneIPorCIDR() schema.SchemaValidateFunc {
return func(val interface{}, key string) (warns []string, errs []error) {
ip, isString := val.(string)
if !isString {
return nil, []error{fmt.Errorf("invalid input for key '%s': not a string", key)}
}

// Check if it's a standalone IP address
if net.ParseIP(ip) != nil {
return
}

// Check if it's an IP with CIDR notation
_, _, err := net.ParseCIDR(ip)
if err != nil {
errs = append(errs, fmt.Errorf("%q is not a valid IP address or CIDR notation: %s", key, ip))
}

return
}
}
28 changes: 28 additions & 0 deletions internal/verify/ip_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package verify_test

import (
"testing"

"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
"github.com/stretchr/testify/assert"
)

func TestValidateStandaloneIPorCIDRWithValidIPReturnNothing(t *testing.T) {
assert := assert.New(t)

for _, ip := range []string{"192.168.1.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "10.0.0.0/24", "2001:0db8:85a3::8a2e:0370:7334/64"} {
warnings, errors := verify.IsStandaloneIPorCIDR()(ip, "key")
assert.Empty(warnings)
assert.Empty(errors)
}
}

func TestValidateStandaloneIPorCIDRWithInvalidIPReturnError(t *testing.T) {
assert := assert.New(t)

for _, ip := range []string{"10.0.0", "256.256.256.256", "2001::85a3::8a2e:0370:7334", "10.0.0.0/34"} {
warnings, errors := verify.IsStandaloneIPorCIDR()(ip, "key")
assert.Empty(warnings)
assert.Len(errors, 1)
}
}
50 changes: 50 additions & 0 deletions internal/verify/uuid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package verify

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/scaleway/scaleway-sdk-go/validation"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
)

// IsUUIDorUUIDWithLocality validates the schema is a UUID or the combination of a locality and a UUID
// e.g. "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or "fr-par-1/6ba7b810-9dad-11d1-80b4-00c04fd430c8".
func IsUUIDorUUIDWithLocality() schema.SchemaValidateFunc {
return func(v interface{}, key string) ([]string, []error) {
return IsUUID()(locality.ExpandID(v), key)
}
}

// IsUUID validates the schema following the canonical UUID format
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
func IsUUID() schema.SchemaValidateFunc {
return func(v interface{}, key string) (warnings []string, errors []error) {
uuid, isString := v.(string)
if !isString {
return nil, []error{fmt.Errorf("invalid UUID for key '%s': not a string", key)}
}

if !validation.IsUUID(uuid) {
return nil, []error{fmt.Errorf("invalid UUID for key '%s': '%s' (%d): format should be 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' (36) and contains valid hexadecimal characters", key, uuid, len(uuid))}
}

return
}
}

func IsUUIDWithLocality() schema.SchemaValidateFunc {
return func(v interface{}, key string) (warnings []string, errors []error) {
uuid, isString := v.(string)
if !isString {
errors = []error{fmt.Errorf("invalid UUID for key '%s': not a string", key)}
return
}
_, subUUID, err := locality.ParseLocalizedID(uuid)
if err != nil {
errors = []error{fmt.Errorf("invalid UUID with locality for key '%s': '%s' (%d): format should be 'locality/uuid'", key, uuid, len(uuid))}
return
}
return IsUUID()(subUUID, key)
}
}
35 changes: 8 additions & 27 deletions scaleway/validation_test.go → internal/verify/uuid_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package scaleway
package verify_test

import (
"testing"

"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
"github.com/stretchr/testify/assert"
)

func TestValidationUUIDWithInvalidUUIDReturnError(t *testing.T) {
assert := assert.New(t)

for _, uuid := range []string{"fr-par/wrong-uuid/resource", "fr-par/wrong-uuid", "wrong-uuid"} {
warnings, errors := validationUUID()(uuid, "key")
warnings, errors := verify.IsUUID()(uuid, "key")
assert.Empty(warnings)
assert.Len(errors, 1)
}
Expand All @@ -19,7 +20,7 @@ func TestValidationUUIDWithInvalidUUIDReturnError(t *testing.T) {
func TestValidationUUIDWithValidUUIDReturnNothing(t *testing.T) {
assert := assert.New(t)

warnings, errors := validationUUID()("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "key")
warnings, errors := verify.IsUUID()("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "key")

assert.Empty(warnings)
assert.Empty(errors)
Expand All @@ -29,7 +30,7 @@ func TestValidationUUIDorUUIDWithLocalityWithValidUUIDReturnNothing(t *testing.T
assert := assert.New(t)

for _, uuid := range []string{"fr-par/6ba7b810-9dad-11d1-80b4-00c04fd430c8", "6ba7b810-9dad-11d1-80b4-00c04fd430c8"} {
warnings, errors := validationUUIDorUUIDWithLocality()(uuid, "key")
warnings, errors := verify.IsUUIDorUUIDWithLocality()(uuid, "key")
assert.Empty(warnings)
assert.Empty(errors)
}
Expand All @@ -39,7 +40,7 @@ func TestValidationUUIDorUUIDWithLocalityWithInvalidUUIDReturnError(t *testing.T
assert := assert.New(t)

for _, uuid := range []string{"fr-par/wrong-uuid/resource", "fr-par/wrong-uuid", "wrong-uuid"} {
warnings, errors := validationUUIDorUUIDWithLocality()(uuid, "key")
warnings, errors := verify.IsUUIDorUUIDWithLocality()(uuid, "key")
assert.Empty(warnings)
assert.Len(errors, 1)
}
Expand All @@ -49,7 +50,7 @@ func TestValidationUUIDWithLocalityWithValidUUIDReturnNothing(t *testing.T) {
assert := assert.New(t)

for _, uuid := range []string{"fr-par/6ba7b810-9dad-11d1-80b4-00c04fd430c8"} {
warnings, errors := validationUUIDWithLocality()(uuid, "key")
warnings, errors := verify.IsUUIDWithLocality()(uuid, "key")
assert.Empty(warnings)
assert.Empty(errors)
}
Expand All @@ -59,28 +60,8 @@ func TestValidationUUIDWithLocalityWithInvalidUUIDReturnError(t *testing.T) {
assert := assert.New(t)

for _, uuid := range []string{"fr-par/wrong-uuid/resource", "fr-par/wrong-uuid", "wrong-uuid", "6ba7b810-9dad-11d1-80b4-00c04fd430c8"} {
warnings, errors := validationUUIDWithLocality()(uuid, "key")
warnings, errors := verify.IsUUIDWithLocality()(uuid, "key")
assert.Empty(warnings)
assert.Len(errors, 1, uuid)
}
}

func TestValidateStandaloneIPorCIDRWithValidIPReturnNothing(t *testing.T) {
assert := assert.New(t)

for _, ip := range []string{"192.168.1.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "10.0.0.0/24", "2001:0db8:85a3::8a2e:0370:7334/64"} {
warnings, errors := validateStandaloneIPorCIDR()(ip, "key")
assert.Empty(warnings)
assert.Empty(errors)
}
}

func TestValidateStandaloneIPorCIDRWithInvalidIPReturnError(t *testing.T) {
assert := assert.New(t)

for _, ip := range []string{"10.0.0", "256.256.256.256", "2001::85a3::8a2e:0370:7334", "10.0.0.0/34"} {
warnings, errors := validateStandaloneIPorCIDR()(ip, "key")
assert.Empty(warnings)
assert.Len(errors, 1)
}
}
3 changes: 2 additions & 1 deletion scaleway/data_source_account_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
accountV3 "github.com/scaleway/scaleway-sdk-go/api/account/v3"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func dataSourceScalewayAccountProject() *schema.Resource {
Expand All @@ -20,7 +21,7 @@ func dataSourceScalewayAccountProject() *schema.Resource {
Computed: true,
Optional: true,
Description: "The ID of the SSH key",
ValidateFunc: validationUUID(),
ValidateFunc: verify.IsUUID(),
}

return &schema.Resource{
Expand Down
3 changes: 2 additions & 1 deletion scaleway/data_source_baremetal_option.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func dataSourceScalewayBaremetalOption() *schema.Resource {
Expand All @@ -25,7 +26,7 @@ func dataSourceScalewayBaremetalOption() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "The ID of the option",
ValidateFunc: validationUUIDorUUIDWithLocality(),
ValidateFunc: verify.IsUUIDorUUIDWithLocality(),
ConflictsWith: []string{"name"},
},
"manageable": {
Expand Down
3 changes: 2 additions & 1 deletion scaleway/data_source_baremetal_os.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func dataSourceScalewayBaremetalOs() *schema.Resource {
Expand All @@ -31,7 +32,7 @@ func dataSourceScalewayBaremetalOs() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "The ID of the os",
ValidateFunc: validationUUIDorUUIDWithLocality(),
ValidateFunc: verify.IsUUIDorUUIDWithLocality(),
ConflictsWith: []string{"name"},
},
"zone": zonal.Schema(),
Expand Down
3 changes: 2 additions & 1 deletion scaleway/data_source_baremetal_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func dataSourceScalewayBaremetalServer() *schema.Resource {
Expand All @@ -21,7 +22,7 @@ func dataSourceScalewayBaremetalServer() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "The ID of the server",
ValidateFunc: validationUUIDorUUIDWithLocality(),
ValidateFunc: verify.IsUUIDorUUIDWithLocality(),
ConflictsWith: []string{"name"},
}

Expand Down
3 changes: 2 additions & 1 deletion scaleway/data_source_block_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
block "github.com/scaleway/scaleway-sdk-go/api/block/v1alpha1"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func dataSourceScalewayBlockSnapshot() *schema.Resource {
Expand All @@ -19,7 +20,7 @@ func dataSourceScalewayBlockSnapshot() *schema.Resource {
Optional: true,
Description: "The ID of the snapshot",
ConflictsWith: []string{"name"},
ValidateFunc: validationUUIDorUUIDWithLocality(),
ValidateFunc: verify.IsUUIDorUUIDWithLocality(),
}

return &schema.Resource{
Expand Down
Loading

0 comments on commit 4296f06

Please sign in to comment.