Skip to content
20 changes: 20 additions & 0 deletions pkg/profiles/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ var (
minStatus uint32 = 100
maxStatus uint32 = 599

errNilMatchAll = fmt.Errorf("null condition \"all\"")
errNilMatchAny = fmt.Errorf("null condition \"any\"")
errRequestMatchField = errors.New("A request match must have a field set")
errResponseMatchField = errors.New("A response match must have a field set")
)
Expand Down Expand Up @@ -66,6 +68,9 @@ func Validate(data []byte) error {
}

for _, route := range serviceProfile.Spec.Routes {
if route == nil {
return fmt.Errorf("ServiceProfile %q has a null route", serviceProfile.Name)
}
if route.Name == "" {
return fmt.Errorf("ServiceProfile %q has a route with no name", serviceProfile.Name)
}
Expand All @@ -83,6 +88,9 @@ func Validate(data []byte) error {
return fmt.Errorf("ServiceProfile %q has a route with an invalid condition: %w", serviceProfile.Name, err)
}
for _, rc := range route.ResponseClasses {
if rc == nil {
return fmt.Errorf("ServiceProfile %q has a null response class", serviceProfile.Name)
}
if rc.Condition == nil {
return fmt.Errorf("ServiceProfile %q has a response class with no condition", serviceProfile.Name)
}
Expand Down Expand Up @@ -119,6 +127,9 @@ func ValidateRequestMatch(reqMatch *sp.RequestMatch) error {
if reqMatch.All != nil {
matchKindSet = true
for _, child := range reqMatch.All {
if child == nil {
return errNilMatchAll
}
err := ValidateRequestMatch(child)
if err != nil {
return err
Expand All @@ -128,6 +139,9 @@ func ValidateRequestMatch(reqMatch *sp.RequestMatch) error {
if reqMatch.Any != nil {
matchKindSet = true
for _, child := range reqMatch.Any {
if child == nil {
return errNilMatchAny
}
err := ValidateRequestMatch(child)
if err != nil {
return err
Expand Down Expand Up @@ -162,6 +176,9 @@ func ValidateResponseMatch(rspMatch *sp.ResponseMatch) error {
if rspMatch.All != nil {
matchKindSet = true
for _, child := range rspMatch.All {
if child == nil {
return errNilMatchAll
}
err := ValidateResponseMatch(child)
if err != nil {
return err
Expand All @@ -171,6 +188,9 @@ func ValidateResponseMatch(rspMatch *sp.ResponseMatch) error {
if rspMatch.Any != nil {
matchKindSet = true
for _, child := range rspMatch.Any {
if child == nil {
return errNilMatchAny
}
err := ValidateResponseMatch(child)
if err != nil {
return err
Expand Down
131 changes: 131 additions & 0 deletions pkg/profiles/profiles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,137 @@ spec:
method: GET
pathRegex: /route-1`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a null route`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
-`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a route with an invalid condition: null condition "all"`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1
all:
-`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a route with an invalid condition: null condition "any"`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1
any:
-`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a null response class`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1
responseClasses:
-`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a response class with an invalid condition: null condition "all"`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1
responseClasses:
- condition:
status:
min: 500
max: 599
all:
-`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a response class with an invalid condition: null condition "any"`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1
responseClasses:
- condition:
status:
min: 500
max: 599
any:
-`,
},
{
err: nil,
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1,
timeout: 1ns`,
},
{
err: errors.New(`ServiceProfile "name.ns.svc.cluster.local" has a route with an invalid timeout: time: invalid duration "one-second"`),
sp: `apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: name.ns.svc.cluster.local
namespace: linkerd-ns
spec:
routes:
- name: name-1
condition:
method: GET
pathRegex: /route-1,
timeout: one-second`,
},
}

for id, exp := range expectations {
Expand Down