ingress: add alternate resource backend
Signed-off-by: Christopher M. Luciano <cmluciano@us.ibm.com>
This commit is contained in:
@@ -1030,6 +1030,88 @@ func TestValidateIngress(t *testing.T) {
|
||||
"spec.rules[0].host",
|
||||
},
|
||||
},
|
||||
"path resource backend and service name are not allowed together": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectErrsOnFields: []string{
|
||||
"spec.rules[0].http.paths[0].backend",
|
||||
},
|
||||
},
|
||||
"path resource backend and service port are not allowed together": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &pathTypeImplementationSpecific,
|
||||
Backend: networking.IngressBackend{
|
||||
ServicePort: intstr.FromInt(80),
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectErrsOnFields: []string{
|
||||
"spec.rules[0].http.paths[0].backend",
|
||||
},
|
||||
},
|
||||
"spec.backend resource and service name are not allowed together": {
|
||||
groupVersion: &networkingv1beta1.SchemeGroupVersion,
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = &networking.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
}
|
||||
},
|
||||
expectErrsOnFields: []string{
|
||||
"spec.backend",
|
||||
},
|
||||
},
|
||||
"spec.backend resource and service port are not allowed together": {
|
||||
groupVersion: &networkingv1beta1.SchemeGroupVersion,
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = &networking.IngressBackend{
|
||||
ServicePort: intstr.FromInt(80),
|
||||
Resource: &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
}
|
||||
},
|
||||
expectErrsOnFields: []string{
|
||||
"spec.backend",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
@@ -1181,6 +1263,11 @@ func TestValidateIngressCreate(t *testing.T) {
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
resourceBackend := &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
}
|
||||
baseIngress := networking.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test123",
|
||||
@@ -1250,6 +1337,31 @@ func TestValidateIngressCreate(t *testing.T) {
|
||||
},
|
||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec.rules[0].http.paths[0].path"), "/([a-z0-9]*)[", "must be a valid regex")},
|
||||
},
|
||||
"Spec.Backend.Resource field not allowed on create": {
|
||||
tweakIngress: func(ingress *networking.Ingress) {
|
||||
ingress.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend}
|
||||
},
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.backend.resource"), "not supported; only service backends are supported in this version")},
|
||||
},
|
||||
"Paths.Backend.Resource field not allowed on create": {
|
||||
tweakIngress: func(ingress *networking.Ingress) {
|
||||
ingress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/([a-z0-9]*)",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
},
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.rules[0].http.paths[0].backend.resource"), "not supported; only service backends are supported in this version")},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
@@ -1277,6 +1389,11 @@ func TestValidateIngressUpdate(t *testing.T) {
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
resourceBackend := &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
}
|
||||
baseIngress := networking.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test123",
|
||||
@@ -1427,6 +1544,151 @@ func TestValidateIngressUpdate(t *testing.T) {
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"new Backend.Resource not allowed on update": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Backend = &defaultBackend
|
||||
newIngress.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend}
|
||||
},
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.backend.resource"), "not supported; only service backends are supported in this version")},
|
||||
},
|
||||
"old Backend.Resource allowed on update": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend}
|
||||
newIngress.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend}
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"changing spec.backend from resource -> no resource": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend}
|
||||
newIngress.Spec.Backend = &defaultBackend
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"changing path backend from resource -> no resource": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
newIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/bar[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"changing path backend from resource -> resource": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
newIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/bar[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"changing path backend from non-resource -> non-resource": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
newIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/bar[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
},
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"changing path backend from non-resource -> resource": {
|
||||
tweakIngresses: func(newIngress, oldIngress *networking.Ingress) {
|
||||
oldIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/foo[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: defaultBackend,
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
newIngress.Spec.Rules = []networking.IngressRule{{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{{
|
||||
Path: "/bar[",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
},
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.rules[0].http.paths[0].backend.resource"), "not supported; only service backends are supported in this version")},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
@@ -1816,3 +2078,151 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateResourceBackendPresent(t *testing.T) {
|
||||
implementationPathType := networking.PathTypeImplementationSpecific
|
||||
defaultBackend := networking.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
resourceBackend := &api.TypedLocalObjectReference{
|
||||
APIGroup: utilpointer.StringPtr("example.com"),
|
||||
Kind: "foo",
|
||||
Name: "bar",
|
||||
}
|
||||
baseIngress := networking.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
Backend: &networking.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &implementationPathType,
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "127.0.0.1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
testCases := map[string]struct {
|
||||
groupVersion *schema.GroupVersion
|
||||
tweakIngress func(ing *networking.Ingress)
|
||||
expectResourceBackend bool
|
||||
}{
|
||||
"nil spec.Backend and no paths": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].Path = ""
|
||||
},
|
||||
expectResourceBackend: false,
|
||||
},
|
||||
"nil spec.Backend.Resource and no paths": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []networking.HTTPIngressPath{}
|
||||
},
|
||||
expectResourceBackend: false,
|
||||
},
|
||||
"non-nil spec.Backend.Resource and no paths": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = &networking.IngressBackend{
|
||||
Resource: resourceBackend,
|
||||
}
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].Path = ""
|
||||
},
|
||||
expectResourceBackend: true,
|
||||
},
|
||||
"nil spec.Backend, one rule with nil HTTP ": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP = nil
|
||||
},
|
||||
expectResourceBackend: false,
|
||||
},
|
||||
"nil spec.Backend, one rule with non-nil HTTP, no paths": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectResourceBackend: false,
|
||||
},
|
||||
"nil spec.Backend, one rule with non-nil HTTP, one path with nil Backend.Resource": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectResourceBackend: false,
|
||||
},
|
||||
"nil spec.Backend, one rule with non-nil HTTP, one path with non-nil Backend.Resource": {
|
||||
tweakIngress: func(ing *networking.Ingress) {
|
||||
ing.Spec.Backend = nil
|
||||
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
PathType: &implementationPathType,
|
||||
Backend: networking.IngressBackend{
|
||||
Resource: resourceBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectResourceBackend: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ingress := baseIngress.DeepCopy()
|
||||
testCase.tweakIngress(ingress)
|
||||
gv := testCase.groupVersion
|
||||
if gv == nil {
|
||||
gv = &networkingv1.SchemeGroupVersion
|
||||
}
|
||||
isBackendAllowed := resourceBackendPresent(ingress)
|
||||
if isBackendAllowed != testCase.expectResourceBackend {
|
||||
t.Errorf("Expected resourceBackendPresent to return: %v, got: %v", testCase.expectResourceBackend, isBackendAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user