Skip to content

Commit

Permalink
Feature/odj 2783 add validation functions for resource network (#204)
Browse files Browse the repository at this point in the history
* ODJ-2783: add validation functions for the type Network

* ODJ-2783: add wait handler method for the type V1DeleteNetworkResponse

* ODJ-2783: add unit tests for the validation functions

* ODJ-2783: add valdiation function for network ID
  • Loading branch information
EmilGeorgiev authored Feb 22, 2024
1 parent 0dac3d4 commit 5f52368
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 1 deletion.
28 changes: 27 additions & 1 deletion pkg/services/iaas-api/v1alpha/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,30 @@ import (
openapiTypes "github.com/SchwarzIT/community-stackit-go-client/pkg/helpers/types"
)

func (*V1CreateNetworkResponse) WaitHandler(ctx context.Context, c *ClientWithResponses, projectID, networkID openapiTypes.UUID) *wait.Handler {
func (*V1CreateNetworkResponse) WaitHandler(ctx context.Context, c *ClientWithResponses, projectID openapiTypes.UUID) *wait.Handler {
return wait.New(func() (res interface{}, done bool, err error) {
resp, err := c.V1ListNetworksInProject(ctx, projectID)
if err != nil {
if strings.Contains(err.Error(), http.StatusText(http.StatusForbidden)) {
return nil, false, nil
}
return nil, false, err
}
if resp.StatusCode() == http.StatusForbidden {
return nil, false, nil
}
if resp.StatusCode() == http.StatusInternalServerError {
return nil, false, nil
}
if resp.JSON200 == nil {
return nil, false, nil
}

return resp, true, nil
})
}

func (*V1DeleteNetworkResponse) WaitHandler(ctx context.Context, c *ClientWithResponses, projectID, networkID openapiTypes.UUID) *wait.Handler {
return wait.New(func() (res interface{}, done bool, err error) {
resp, err := c.V1GetNetwork(ctx, projectID, networkID)
if err != nil {
Expand All @@ -25,6 +48,9 @@ func (*V1CreateNetworkResponse) WaitHandler(ctx context.Context, c *ClientWithRe
if resp.StatusCode() == http.StatusInternalServerError {
return nil, false, nil
}
if resp.StatusCode() == http.StatusNotFound {
return nil, false, nil
}
if resp.JSON200 == nil {
return nil, false, nil
}
Expand Down
64 changes: 64 additions & 0 deletions pkg/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,67 @@ func ErrorIsOneOf(err error, msgs ...string) bool {
}
return false
}

// NetworkName validates a given network name
func NetworkName(name string) error {
exp := `^[A-Za-z0-9]+((-|_|\s|\.)[A-Za-z0-9]+)*$`
r := regexp.MustCompile(exp)
if !r.MatchString(name) {
return fmt.Errorf("invalid network name: %s. valid name must patch the expression: %s", name, exp)
}
if len(name) > 63 {
return fmt.Errorf("invalid network name. The length of the name must contains maximum 63 characters")
}
return nil
}

// NameServer validates a given server name
func NameServer(name string) error {
exp := "((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"
r := regexp.MustCompile(exp)
if !r.MatchString(name) {
return fmt.Errorf("invalid server name: %s. valid name must match the expression: %s", name, exp)
}
return nil
}

// PrefixLengthV4 validates a given server name.
func PrefixLengthV4(prefix int64) error {
if prefix < 22 || prefix > 29 {
return fmt.Errorf("invalid prefix length: %d. The length must be between 22 and 29", prefix)
}
return nil
}

// Prefix validates a given prefix
func Prefix(pr string) error {
exp := "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\/(3[0-2]|2[0-9]|1[0-9]|[0-9]))$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\\/((1(1[0-9]|2[0-8]))|([0-9][0-9])|([0-9])))?$"
r := regexp.MustCompile(exp)
if !r.MatchString(pr) {
return fmt.Errorf("invalid prefix: %s. valid prefix shuld match expression: %s", pr, exp)
}
return nil
}

// PublicIP validates a given ID address
func PublicIP(ip string) error {
exp := "((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"
r := regexp.MustCompile(exp)
if !r.MatchString(ip) {
return fmt.Errorf("invalid public IP: %s. valid IP must match the expression: %s", ip, exp)
}
return nil
}

func NetworkID(id string) error {
exp := "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
r := regexp.MustCompile(exp)
if !r.MatchString(id) {
return fmt.Errorf("invalid networkID: %s. valid ID must match the expression: %s", id, exp)
}
if len(id) != 36 {
return fmt.Errorf("invalid networkID: %s. Valid ID must be exactly 36 characters", id)
}

return nil
}
135 changes: 135 additions & 0 deletions pkg/validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,138 @@ func TestErrorIsOneOf(t *testing.T) {
})
}
}

func TestNetworkName(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"no ok", args{"Invalid Name!"}, true},
{"ok [1]", args{"My-Example_String.123"}, false},
{"ok [2]", args{"Hello_World"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.NetworkName(tt.args.name); (err != nil) != tt.wantErr {
t.Errorf("NetworkName() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestNameServer(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"not ok [1]", args{"256.100.50.25"}, true},
{"not ok [2]", args{"GHT:::1200:::0000"}, true},
{"ok [1]", args{"192.168.1.1"}, false},
{"ok [2]", args{"2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.NameServer(tt.args.name); (err != nil) != tt.wantErr {
t.Errorf("NameServer() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestPrefixLength(t *testing.T) {
type args struct {
prefix int64
}
tests := []struct {
name string
args args
wantErr bool
}{
{"not ok [1]", args{21}, true},
{"not ok [2]", args{30}, true},
{"ok [1]", args{22}, false},
{"ok [2]", args{29}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.PrefixLengthV4(tt.args.prefix); (err != nil) != tt.wantErr {
t.Errorf("NameServer() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestPrefix(t *testing.T) {
type args struct {
prefix string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"not ok", args{"999.999.999.999/32"}, true},
{"ok [1]", args{"192.168.1.1/24"}, false},
{"ok [2]", args{"fe80::1ff:fe23:4567:890a/64"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.Prefix(tt.args.prefix); (err != nil) != tt.wantErr {
t.Errorf("Prefix() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestPublicIP(t *testing.T) {
type args struct {
ip string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"not ok", args{"999.999.999.999"}, true},
{"ok [1]", args{"192.168.1.1"}, false},
{"ok [2]", args{"2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.PublicIP(tt.args.ip); (err != nil) != tt.wantErr {
t.Errorf("PublicIP() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestNetworkID(t *testing.T) {
type args struct {
id string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"not ok", args{"14b0cd73-3342-44a3-a10e-q1bc20af4497"}, true},
{"not ok", args{"14b0cd73-3342-44a3-a10e-q1bc20af44979"}, true},
{"ok [1]", args{"14b0cd73-3342-44a3-a10e-f1bc20af4497"}, false},
{"ok [2]", args{"14b0cd52-6677-44a3-a10e-f1bc21af4445"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validate.NetworkID(tt.args.id); (err != nil) != tt.wantErr {
t.Errorf("NetworkID() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

0 comments on commit 5f52368

Please sign in to comment.