Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CW 2023 merge iteration 1 #2750

Closed
wants to merge 9 commits into from
19 changes: 15 additions & 4 deletions cmd/webhook/admission/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zalando/skipper/dataclients/kubernetes/definitions"
)

const (
Expand Down Expand Up @@ -122,6 +123,16 @@ func TestRouteGroupAdmitter(t *testing.T) {
inputFile: "rg-with-invalid-eskip-filters-and-predicates.json",
message: "parse failed after token status, last route id: , position 11: syntax error\\nparse failed after token Method, last route id: Method, position 6: syntax error",
},
{
name: "invalid routgroup multiple filters per json/yaml array item",
inputFile: "rg-with-multiple-filters.json",
message: `single filter expected at \"status(201) -> inlineContent(\\\"hi\\\")\"\nsingle filter expected at \" \"`,
},
{
name: "invalid routgroup multiple predicates per json/yaml array item",
inputFile: "rg-with-multiple-predicates.json",
message: `single predicate expected at \"Method(\\\"GET\\\") && Path(\\\"/\\\")\"\nsingle predicate expected at \" \"`,
},
} {
t.Run(tc.name, func(t *testing.T) {
expectedResponse := responseAllowedFmt
Expand All @@ -136,7 +147,7 @@ func TestRouteGroupAdmitter(t *testing.T) {
req.Header.Set("Content-Type", "application/json")

w := httptest.NewRecorder()
rgAdm := &RouteGroupAdmitter{}
rgAdm := &RouteGroupAdmitter{RouteGroupValidator: &definitions.RouteGroupValidator{}}

h := Handler(rgAdm)
h(w, req)
Expand Down Expand Up @@ -200,7 +211,7 @@ func TestIngressAdmitter(t *testing.T) {
req.Header.Set("Content-Type", "application/json")

w := httptest.NewRecorder()
ingressAdm := &IngressAdmitter{}
ingressAdm := &IngressAdmitter{IngressValidator: &definitions.IngressV1Validator{}}

h := Handler(ingressAdm)
h(w, req)
Expand All @@ -217,8 +228,8 @@ func TestIngressAdmitter(t *testing.T) {
}

func TestMalformedRequests(t *testing.T) {
routeGroupHandler := Handler(&RouteGroupAdmitter{})
ingressHandler := Handler(&IngressAdmitter{})
routeGroupHandler := Handler(&RouteGroupAdmitter{RouteGroupValidator: &definitions.RouteGroupValidator{}})
ingressHandler := Handler(&IngressAdmitter{IngressValidator: &definitions.IngressV1Validator{}})

for _, tc := range []struct {
name string
Expand Down
49 changes: 49 additions & 0 deletions cmd/webhook/admission/testdata/rg/rg-with-multiple-filters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"request": {
"uid": "req-uid",
"name": "req1",
"operation": "create",
"kind": {
"group": "zalando",
"version": "v1",
"kind": "RouteGroup"
},
"namespace": "n1",
"object": {
"metadata": {
"name": "rg1",
"namespace": "n1"
},
"spec": {
"backends": [
{
"name": "backend",
"type": "shunt"
}
],
"defaultBackends": [
{
"backendName": "backend"
}
],
"routes": [
{
"backends": [
{
"backendName": "backend"
}
],
"filters": [
"status(201) -> inlineContent(\"hi\")",
" "
],
"path": "/",
"predicates": [
"Method(\"GET\")"
]
}
]
}
}
}
}
49 changes: 49 additions & 0 deletions cmd/webhook/admission/testdata/rg/rg-with-multiple-predicates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"request": {
"uid": "req-uid",
"name": "req1",
"operation": "create",
"kind": {
"group": "zalando",
"version": "v1",
"kind": "RouteGroup"
},
"namespace": "n1",
"object": {
"metadata": {
"name": "rg1",
"namespace": "n1"
},
"spec": {
"backends": [
{
"name": "backend",
"type": "shunt"
}
],
"defaultBackends": [
{
"backendName": "backend"
}
],
"routes": [
{
"backends": [
{
"backendName": "backend"
}
],
"filters": [
"status(201)"
],
"path": "/",
"predicates": [
"Method(\"GET\") && Path(\"/\")",
" "
]
}
]
}
}
}
}
8 changes: 7 additions & 1 deletion dataclients/kubernetes/definitions/definitions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package definitions_test

import (
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -18,10 +19,15 @@ func TestValidateRouteGroups(t *testing.T) {
data, err := os.ReadFile("testdata/errorwrapdata/routegroups.json")
require.NoError(t, err)

logs, err := os.ReadFile("testdata/errorwrapdata/errors.log")
require.NoError(t, err)

logsString := strings.TrimSuffix(string(logs), "\n")

rgl, err := definitions.ParseRouteGroupsJSON(data)
require.NoError(t, err)

err = definitions.ValidateRouteGroups(&rgl)

assert.EqualError(t, err, "route group without name\nerror in route group default/rg1: route group without backend")
assert.EqualError(t, err, logsString)
}
2 changes: 0 additions & 2 deletions dataclients/kubernetes/definitions/routegroups.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ var (
errRouteGroupWithoutName = errors.New("route group without name")
errRouteGroupWithoutSpec = errors.New("route group without spec")
errInvalidRouteSpec = errors.New("invalid route spec")
errInvalidPredicate = errors.New("invalid predicate")
errInvalidFilter = errors.New("invalid filter")
errInvalidMethod = errors.New("invalid method")
errBothPathAndPathSubtree = errors.New("path and path subtree in the same route")
errMissingBackendReference = errors.New("missing backend reference")
Expand Down
32 changes: 20 additions & 12 deletions dataclients/kubernetes/definitions/routegroupvalidator.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package definitions

import (
"errors"
"fmt"

"github.com/zalando/skipper/eskip"
)

type RouteGroupValidator struct{}

var (
errSingleFilterExpected = errors.New("single filter expected")
errSinglePredicateExpected = errors.New("single predicate expected")
)

var defaultRouteGroupValidator = &RouteGroupValidator{}

// ValidateRouteGroup validates a RouteGroupItem
Expand Down Expand Up @@ -56,8 +64,12 @@ func (rgv *RouteGroupValidator) filtersValidation(item *RouteGroupItem) error {
var errs []error
for _, r := range item.Spec.Routes {
for _, f := range r.Filters {
_, err := eskip.ParseFilters(f)
errs = append(errs, err)
filters, err := eskip.ParseFilters(f)
if err != nil {
errs = append(errs, err)
} else if len(filters) != 1 {
errs = append(errs, fmt.Errorf("%w at %q", errSingleFilterExpected, f))
}
}
}

Expand All @@ -68,8 +80,12 @@ func (rgv *RouteGroupValidator) predicatesValidation(item *RouteGroupItem) error
var errs []error
for _, r := range item.Spec.Routes {
for _, p := range r.Predicates {
_, err := eskip.ParsePredicates(p)
errs = append(errs, err)
predicates, err := eskip.ParsePredicates(p)
if err != nil {
errs = append(errs, err)
} else if len(predicates) != 1 {
errs = append(errs, fmt.Errorf("%w at %q", errSinglePredicateExpected, p))
}
}
}
return errorsJoin(errs...)
Expand Down Expand Up @@ -131,14 +147,6 @@ func (r *RouteSpec) validate(hasDefault bool, backends map[string]bool) error {
return errBothPathAndPathSubtree
}

if hasEmpty(r.Predicates) {
return errInvalidPredicate
}

if hasEmpty(r.Filters) {
return errInvalidFilter
}

if hasEmpty(r.Methods) {
return errInvalidMethod
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
route group without name
error in route group default/rg1: route group without backend
single predicate expected at "Path(\"/foo\") && Method(\"GET\")"
single predicate expected at ""
single filter expected at "inlineContent(\"/foo\") -> status(200)"
single filter expected at " "
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,41 @@
"kind": "RouteGroup",
"spec": {
"backends": [
{
{
"name": "shunt",
"type": "shunt"
}
],
"hosts": [
"test.example.com"
],
"routes": [
{
"backends": [
{
"backendName": "shunt"
}
],
"filters": [
"inlineContent(\"/foo\")"
],
"path": "/foo"
}
]
}
},
{
"apiVersion": "zalando.org/v1",
"metadata": {
"name": "rg1"
},
"kind": "RouteGroup",
"spec": {
"backends": [
{
"name": "shunt",
"type": "shunt"
}
}
],
"hosts": [
"test.example.com"
Expand All @@ -60,13 +91,49 @@
"backendName": "shunt"
}
],
"predicates": [
"Path(\"/foo\") && Method(\"GET\")",
""
],
"filters": [
"inlineContent(\"/foo\")"
],
"path": "/foo"
}
]
}
},
{
"apiVersion": "zalando.org/v1",
"metadata": {
"name": "rg1"
},
"kind": "RouteGroup",
"spec": {
"backends": [
{
"name": "shunt",
"type": "shunt"
}
],
"hosts": [
"test.example.com"
],
"routes": [
{
"backends": [
{
"backendName": "shunt"
}
],
"filters": [
"inlineContent(\"/foo\") -> status(200)",
" "
],
"path": "/foo"
}
]
}
}
]
}
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
test-route-group
invalid filter
single filter expected
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
test-route-group
invalid predicate
single predicate expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
single filter expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: zalando.org/v1
kind: RouteGroup
metadata:
name: test-route-group
spec:
hosts:
- example.org
backends:
- name: app
type: service
serviceName: app-svc
servicePort: 80
defaultBackends:
- backendName: app
routes:
- path: /
methods:
- GET
- HEAD
predicates:
- Foo("X-Bar", "42")
filters:
- foo(42) -> bar(24)
backends:
- backendName: app
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
single predicate expected
Loading