Merge pull request #119150 from tnqn/external-traffic-policy-external-ips

Allow specifying ExternalTrafficPolicy for Services with ExternalIPs
This commit is contained in:
Kubernetes Prow Robot
2023-08-31 08:24:48 -07:00
committed by GitHub
14 changed files with 286 additions and 23 deletions

View File

@@ -7,6 +7,7 @@ rules:
- k8s.io/kubernetes/pkg/api/legacyscheme - k8s.io/kubernetes/pkg/api/legacyscheme
- k8s.io/kubernetes/pkg/api/service - k8s.io/kubernetes/pkg/api/service
- k8s.io/kubernetes/pkg/api/v1/pod - k8s.io/kubernetes/pkg/api/v1/pod
- k8s.io/kubernetes/pkg/api/v1/service
- k8s.io/kubernetes/pkg/apis/apps - k8s.io/kubernetes/pkg/apis/apps
- k8s.io/kubernetes/pkg/apis/autoscaling - k8s.io/kubernetes/pkg/apis/autoscaling
- k8s.io/kubernetes/pkg/apis/core - k8s.io/kubernetes/pkg/apis/core

View File

@@ -67,6 +67,13 @@ func GetLoadBalancerSourceRanges(service *api.Service) (utilnet.IPNetSet, error)
return ipnets, nil return ipnets, nil
} }
// ExternallyAccessible checks if service is externally accessible.
func ExternallyAccessible(service *api.Service) bool {
return service.Spec.Type == api.ServiceTypeLoadBalancer ||
service.Spec.Type == api.ServiceTypeNodePort ||
(service.Spec.Type == api.ServiceTypeClusterIP && len(service.Spec.ExternalIPs) > 0)
}
// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic. // RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic.
func RequestsOnlyLocalTraffic(service *api.Service) bool { func RequestsOnlyLocalTraffic(service *api.Service) bool {
if service.Spec.Type != api.ServiceTypeLoadBalancer && if service.Spec.Type != api.ServiceTypeLoadBalancer &&

View File

@@ -129,6 +129,49 @@ func TestAllowAll(t *testing.T) {
checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0") checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0")
} }
func TestExternallyAccessible(t *testing.T) {
checkExternallyAccessible := func(expect bool, service *api.Service) {
res := ExternallyAccessible(service)
if res != expect {
t.Errorf("Expected ExternallyAccessible = %v, got %v", expect, res)
}
}
checkExternallyAccessible(false, &api.Service{})
checkExternallyAccessible(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeClusterIP,
},
})
checkExternallyAccessible(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeClusterIP,
ExternalIPs: []string{"1.2.3.4"},
},
})
checkExternallyAccessible(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeLoadBalancer,
},
})
checkExternallyAccessible(true, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeNodePort,
},
})
checkExternallyAccessible(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeExternalName,
},
})
checkExternallyAccessible(false, &api.Service{
Spec: api.ServiceSpec{
Type: api.ServiceTypeExternalName,
ExternalIPs: []string{"1.2.3.4"},
},
})
}
func TestRequestsOnlyLocalTraffic(t *testing.T) { func TestRequestsOnlyLocalTraffic(t *testing.T) {
checkRequestsOnlyLocalTraffic := func(requestsOnlyLocalTraffic bool, service *api.Service) { checkRequestsOnlyLocalTraffic := func(requestsOnlyLocalTraffic bool, service *api.Service) {
res := RequestsOnlyLocalTraffic(service) res := RequestsOnlyLocalTraffic(service)

View File

@@ -67,10 +67,16 @@ func GetLoadBalancerSourceRanges(service *v1.Service) (utilnet.IPNetSet, error)
return ipnets, nil return ipnets, nil
} }
// ExternalPolicyLocal checks if service has ETP = Local. // ExternallyAccessible checks if service is externally accessible.
func ExternallyAccessible(service *v1.Service) bool {
return service.Spec.Type == v1.ServiceTypeLoadBalancer ||
service.Spec.Type == v1.ServiceTypeNodePort ||
(service.Spec.Type == v1.ServiceTypeClusterIP && len(service.Spec.ExternalIPs) > 0)
}
// ExternalPolicyLocal checks if service is externally accessible and has ETP = Local.
func ExternalPolicyLocal(service *v1.Service) bool { func ExternalPolicyLocal(service *v1.Service) bool {
if service.Spec.Type != v1.ServiceTypeLoadBalancer && if !ExternallyAccessible(service) {
service.Spec.Type != v1.ServiceTypeNodePort {
return false return false
} }
return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyLocal return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyLocal

View File

@@ -129,6 +129,49 @@ func TestAllowAll(t *testing.T) {
checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0") checkAllowAll(true, "192.168.0.1/32", "0.0.0.0/0")
} }
func TestExternallyAccessible(t *testing.T) {
checkExternallyAccessible := func(expect bool, service *v1.Service) {
res := ExternallyAccessible(service)
if res != expect {
t.Errorf("Expected ExternallyAccessible = %v, got %v", expect, res)
}
}
checkExternallyAccessible(false, &v1.Service{})
checkExternallyAccessible(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
},
})
checkExternallyAccessible(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ExternalIPs: []string{"1.2.3.4"},
},
})
checkExternallyAccessible(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
})
checkExternallyAccessible(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
},
})
checkExternallyAccessible(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeExternalName,
},
})
checkExternallyAccessible(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeExternalName,
ExternalIPs: []string{"1.2.3.4"},
},
})
}
func TestExternalPolicyLocal(t *testing.T) { func TestExternalPolicyLocal(t *testing.T) {
checkExternalPolicyLocal := func(requestsOnlyLocalTraffic bool, service *v1.Service) { checkExternalPolicyLocal := func(requestsOnlyLocalTraffic bool, service *v1.Service) {
res := ExternalPolicyLocal(service) res := ExternalPolicyLocal(service)
@@ -144,6 +187,26 @@ func TestExternalPolicyLocal(t *testing.T) {
Type: v1.ServiceTypeClusterIP, Type: v1.ServiceTypeClusterIP,
}, },
}) })
checkExternalPolicyLocal(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ExternalIPs: []string{"1.2.3.4"},
},
})
checkExternalPolicyLocal(false, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ExternalIPs: []string{"1.2.3.4"},
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyCluster,
},
})
checkExternalPolicyLocal(true, &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ExternalIPs: []string{"1.2.3.4"},
ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
},
})
checkExternalPolicyLocal(false, &v1.Service{ checkExternalPolicyLocal(false, &v1.Service{
Spec: v1.ServiceSpec{ Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort, Type: v1.ServiceTypeNodePort,

View File

@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/api/v1/service"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/parsers" "k8s.io/kubernetes/pkg/util/parsers"
"k8s.io/utils/pointer" "k8s.io/utils/pointer"
@@ -122,11 +123,9 @@ func SetDefaults_Service(obj *v1.Service) {
sp.TargetPort = intstr.FromInt32(sp.Port) sp.TargetPort = intstr.FromInt32(sp.Port)
} }
} }
// Defaults ExternalTrafficPolicy field for NodePort / LoadBalancer service // Defaults ExternalTrafficPolicy field for externally-accessible service
// to Global for consistency. // to Global for consistency.
if (obj.Spec.Type == v1.ServiceTypeNodePort || if service.ExternallyAccessible(obj) && obj.Spec.ExternalTrafficPolicy == "" {
obj.Spec.Type == v1.ServiceTypeLoadBalancer) &&
obj.Spec.ExternalTrafficPolicy == "" {
obj.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyCluster obj.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyCluster
} }

View File

@@ -1631,6 +1631,27 @@ func TestSetDefaultServiceExternalTraffic(t *testing.T) {
if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster { if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster {
t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy) t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy)
} }
in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeClusterIP, ExternalIPs: []string{"1.2.3.4"}}}
obj = roundTrip(t, runtime.Object(in))
out = obj.(*v1.Service)
if out.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyCluster {
t.Errorf("Expected ExternalTrafficPolicy to be %v, got %v", v1.ServiceExternalTrafficPolicyCluster, out.Spec.ExternalTrafficPolicy)
}
in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeClusterIP}}
obj = roundTrip(t, runtime.Object(in))
out = obj.(*v1.Service)
if out.Spec.ExternalTrafficPolicy != "" {
t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
}
in = &v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeExternalName}}
obj = roundTrip(t, runtime.Object(in))
out = obj.(*v1.Service)
if out.Spec.ExternalTrafficPolicy != "" {
t.Errorf("Expected ExternalTrafficPolicy to be empty, got %v", out.Spec.ExternalTrafficPolicy)
}
} }
func TestSetDefaultNamespace(t *testing.T) { func TestSetDefaultNamespace(t *testing.T) {

View File

@@ -5332,10 +5332,6 @@ func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bo
return allErrs return allErrs
} }
func needsExternalTrafficPolicy(svc *core.Service) bool {
return svc.Spec.Type == core.ServiceTypeLoadBalancer || svc.Spec.Type == core.ServiceTypeNodePort
}
var validExternalTrafficPolicies = sets.NewString( var validExternalTrafficPolicies = sets.NewString(
string(core.ServiceExternalTrafficPolicyCluster), string(core.ServiceExternalTrafficPolicyCluster),
string(core.ServiceExternalTrafficPolicyLocal)) string(core.ServiceExternalTrafficPolicyLocal))
@@ -5345,10 +5341,10 @@ func validateServiceExternalTrafficPolicy(service *core.Service) field.ErrorList
fldPath := field.NewPath("spec") fldPath := field.NewPath("spec")
if !needsExternalTrafficPolicy(service) { if !apiservice.ExternallyAccessible(service) {
if service.Spec.ExternalTrafficPolicy != "" { if service.Spec.ExternalTrafficPolicy != "" {
allErrs = append(allErrs, field.Invalid(fldPath.Child("externalTrafficPolicy"), service.Spec.ExternalTrafficPolicy, allErrs = append(allErrs, field.Invalid(fldPath.Child("externalTrafficPolicy"), service.Spec.ExternalTrafficPolicy,
"may only be set when `type` is 'NodePort' or 'LoadBalancer'")) "may only be set for externally-accessible services"))
} }
} else { } else {
if service.Spec.ExternalTrafficPolicy == "" { if service.Spec.ExternalTrafficPolicy == "" {

View File

@@ -14542,27 +14542,38 @@ func TestValidateServiceCreate(t *testing.T) {
}, { }, {
name: "invalid publicIPs localhost", name: "invalid publicIPs localhost",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyCluster
s.Spec.ExternalIPs = []string{"127.0.0.1"} s.Spec.ExternalIPs = []string{"127.0.0.1"}
}, },
numErrs: 1, numErrs: 1,
}, { }, {
name: "invalid publicIPs unspecified", name: "invalid publicIPs unspecified",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyCluster
s.Spec.ExternalIPs = []string{"0.0.0.0"} s.Spec.ExternalIPs = []string{"0.0.0.0"}
}, },
numErrs: 1, numErrs: 1,
}, { }, {
name: "invalid publicIPs loopback", name: "invalid publicIPs loopback",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyCluster
s.Spec.ExternalIPs = []string{"127.0.0.1"} s.Spec.ExternalIPs = []string{"127.0.0.1"}
}, },
numErrs: 1, numErrs: 1,
}, { }, {
name: "invalid publicIPs host", name: "invalid publicIPs host",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyCluster
s.Spec.ExternalIPs = []string{"myhost.mydomain"} s.Spec.ExternalIPs = []string{"myhost.mydomain"}
}, },
numErrs: 1, numErrs: 1,
}, {
name: "valid publicIPs",
tweakSvc: func(s *core.Service) {
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyCluster
s.Spec.ExternalIPs = []string{"1.2.3.4"}
},
numErrs: 0,
}, { }, {
name: "dup port name", name: "dup port name",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
@@ -15540,6 +15551,13 @@ func TestValidateServiceExternalTrafficPolicy(t *testing.T) {
s.Spec.HealthCheckNodePort = 34567 s.Spec.HealthCheckNodePort = 34567
}, },
numErrs: 2, numErrs: 2,
}, {
name: "cannot set externalTrafficPolicy field on ExternalName service",
tweakSvc: func(s *core.Service) {
s.Spec.Type = core.ServiceTypeExternalName
s.Spec.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyLocal
},
numErrs: 1,
}, { }, {
name: "externalTrafficPolicy is required on NodePort service", name: "externalTrafficPolicy is required on NodePort service",
tweakSvc: func(s *core.Service) { tweakSvc: func(s *core.Service) {
@@ -15552,6 +15570,13 @@ func TestValidateServiceExternalTrafficPolicy(t *testing.T) {
s.Spec.Type = core.ServiceTypeLoadBalancer s.Spec.Type = core.ServiceTypeLoadBalancer
}, },
numErrs: 1, numErrs: 1,
}, {
name: "externalTrafficPolicy is required on ClusterIP service with externalIPs",
tweakSvc: func(s *core.Service) {
s.Spec.Type = core.ServiceTypeClusterIP
s.Spec.ExternalIPs = []string{"1.2.3,4"}
},
numErrs: 1,
}, },
} }

View File

@@ -2,6 +2,7 @@ rules:
- selectorRegexp: k8s[.]io/kubernetes/pkg - selectorRegexp: k8s[.]io/kubernetes/pkg
allowedPrefixes: allowedPrefixes:
- k8s.io/kubernetes/pkg/api/legacyscheme - k8s.io/kubernetes/pkg/api/legacyscheme
- k8s.io/kubernetes/pkg/api/v1/service
- k8s.io/kubernetes/pkg/apis/admission - k8s.io/kubernetes/pkg/apis/admission
- k8s.io/kubernetes/pkg/apis/admission/install - k8s.io/kubernetes/pkg/apis/admission/install
- k8s.io/kubernetes/pkg/apis/admission/v1 - k8s.io/kubernetes/pkg/apis/admission/v1

View File

@@ -277,7 +277,7 @@ func dropTypeDependentFields(newSvc *api.Service, oldSvc *api.Service) {
// If a user is switching to a type that doesn't need ExternalTrafficPolicy // If a user is switching to a type that doesn't need ExternalTrafficPolicy
// AND they did not change this field, it is safe to drop it. // AND they did not change this field, it is safe to drop it.
if needsExternalTrafficPolicy(oldSvc) && !needsExternalTrafficPolicy(newSvc) && sameExternalTrafficPolicy(oldSvc, newSvc) { if serviceapi.ExternallyAccessible(oldSvc) && !serviceapi.ExternallyAccessible(newSvc) && sameExternalTrafficPolicy(oldSvc, newSvc) {
newSvc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicy("") newSvc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicy("")
} }
@@ -376,10 +376,6 @@ func sameLoadBalancerClass(oldSvc, newSvc *api.Service) bool {
return *oldSvc.Spec.LoadBalancerClass == *newSvc.Spec.LoadBalancerClass return *oldSvc.Spec.LoadBalancerClass == *newSvc.Spec.LoadBalancerClass
} }
func needsExternalTrafficPolicy(svc *api.Service) bool {
return svc.Spec.Type == api.ServiceTypeNodePort || svc.Spec.Type == api.ServiceTypeLoadBalancer
}
func sameExternalTrafficPolicy(oldSvc, newSvc *api.Service) bool { func sameExternalTrafficPolicy(oldSvc, newSvc *api.Service) bool {
return oldSvc.Spec.ExternalTrafficPolicy == newSvc.Spec.ExternalTrafficPolicy return oldSvc.Spec.ExternalTrafficPolicy == newSvc.Spec.ExternalTrafficPolicy
} }

View File

@@ -510,6 +510,18 @@ func TestDropTypeDependentFields(t *testing.T) {
svc.Spec.Ports[i].NodePort += 100 svc.Spec.Ports[i].NodePort += 100
} }
} }
setExternalIPs := func(svc *api.Service) {
svc.Spec.ExternalIPs = []string{"1.1.1.1"}
}
clearExternalIPs := func(svc *api.Service) {
svc.Spec.ExternalIPs = nil
}
setExternalTrafficPolicyCluster := func(svc *api.Service) {
svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyCluster
}
clearExternalTrafficPolicy := func(svc *api.Service) {
svc.Spec.ExternalTrafficPolicy = ""
}
clearIPFamilies := func(svc *api.Service) { clearIPFamilies := func(svc *api.Service) {
svc.Spec.IPFamilies = nil svc.Spec.IPFamilies = nil
} }
@@ -651,7 +663,7 @@ func TestDropTypeDependentFields(t *testing.T) {
name: "don't clear changed healthCheckNodePort", name: "don't clear changed healthCheckNodePort",
svc: makeValidServiceCustom(setTypeLoadBalancer, setHCNodePort), svc: makeValidServiceCustom(setTypeLoadBalancer, setHCNodePort),
patch: patches(setTypeClusterIP, changeHCNodePort), patch: patches(setTypeClusterIP, changeHCNodePort),
expect: makeValidServiceCustom(setHCNodePort, changeHCNodePort), expect: makeValidServiceCustom(setHCNodePort, changeHCNodePort, clearExternalTrafficPolicy),
}, { // allocatedLoadBalancerNodePorts cases }, { // allocatedLoadBalancerNodePorts cases
name: "clear allocatedLoadBalancerNodePorts true -> true", name: "clear allocatedLoadBalancerNodePorts true -> true",
svc: makeValidServiceCustom(setTypeLoadBalancer, setAllocateLoadBalancerNodePortsTrue), svc: makeValidServiceCustom(setTypeLoadBalancer, setAllocateLoadBalancerNodePortsTrue),
@@ -722,6 +734,11 @@ func TestDropTypeDependentFields(t *testing.T) {
svc: makeValidServiceCustom(setTypeLoadBalancer, setLoadBalancerClass), svc: makeValidServiceCustom(setTypeLoadBalancer, setLoadBalancerClass),
patch: nil, patch: nil,
expect: makeValidServiceCustom(setTypeLoadBalancer, setLoadBalancerClass), expect: makeValidServiceCustom(setTypeLoadBalancer, setLoadBalancerClass),
}, {
name: "clear externalTrafficPolicy when removing externalIPs for Type=ClusterIP",
svc: makeValidServiceCustom(setTypeClusterIP, setExternalIPs, setExternalTrafficPolicyCluster),
patch: patches(clearExternalIPs),
expect: makeValidServiceCustom(setTypeClusterIP, clearExternalTrafficPolicy),
}} }}
for _, tc := range testCases { for _, tc := range testCases {
@@ -759,6 +776,9 @@ func TestDropTypeDependentFields(t *testing.T) {
if !reflect.DeepEqual(result.Spec.LoadBalancerClass, tc.expect.Spec.LoadBalancerClass) { if !reflect.DeepEqual(result.Spec.LoadBalancerClass, tc.expect.Spec.LoadBalancerClass) {
t.Errorf("failed %q: expected LoadBalancerClass %v, got %v", tc.name, tc.expect.Spec.LoadBalancerClass, result.Spec.LoadBalancerClass) t.Errorf("failed %q: expected LoadBalancerClass %v, got %v", tc.name, tc.expect.Spec.LoadBalancerClass, result.Spec.LoadBalancerClass)
} }
if !reflect.DeepEqual(result.Spec.ExternalTrafficPolicy, tc.expect.Spec.ExternalTrafficPolicy) {
t.Errorf("failed %q: expected ExternalTrafficPolicy %v, got %v", tc.name, tc.expect.Spec.ExternalTrafficPolicy, result.Spec.ExternalTrafficPolicy)
}
}) })
} }
} }

View File

@@ -4,6 +4,7 @@
- k8s.io/apiserver/pkg/util/feature - k8s.io/apiserver/pkg/util/feature
- k8s.io/component-base/featuregate/testing - k8s.io/component-base/featuregate/testing
- k8s.io/kubernetes/pkg/apis/core - k8s.io/kubernetes/pkg/apis/core
- k8s.io/kubernetes/pkg/api/v1/service
- k8s.io/kubernetes/pkg/features - k8s.io/kubernetes/pkg/features
- k8s.io/kubernetes/pkg/fieldpath - k8s.io/kubernetes/pkg/fieldpath
- k8s.io/kubernetes/pkg/util - k8s.io/kubernetes/pkg/util

View File

@@ -29,7 +29,7 @@ import (
// Test_ExternalNameServiceStopsDefaultingInternalTrafficPolicy tests that Services no longer default // Test_ExternalNameServiceStopsDefaultingInternalTrafficPolicy tests that Services no longer default
// the internalTrafficPolicy field when Type is ExternalName. This test exists due to historic reasons where // the internalTrafficPolicy field when Type is ExternalName. This test exists due to historic reasons where
// the internalTrafficPolicy field was being defaulted in older versions. New versions stop defauting the // the internalTrafficPolicy field was being defaulted in older versions. New versions stop defaulting the
// field and drop on read, but for compatibility reasons we still accept the field. // field and drop on read, but for compatibility reasons we still accept the field.
func Test_ExternalNameServiceStopsDefaultingInternalTrafficPolicy(t *testing.T) { func Test_ExternalNameServiceStopsDefaultingInternalTrafficPolicy(t *testing.T) {
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd()) server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
@@ -74,7 +74,7 @@ func Test_ExternalNameServiceStopsDefaultingInternalTrafficPolicy(t *testing.T)
// Test_ExternalNameServiceDropsInternalTrafficPolicy tests that Services accepts the internalTrafficPolicy field on Create, // Test_ExternalNameServiceDropsInternalTrafficPolicy tests that Services accepts the internalTrafficPolicy field on Create,
// but drops the field on read. This test exists due to historic reasons where the internalTrafficPolicy field was being defaulted // but drops the field on read. This test exists due to historic reasons where the internalTrafficPolicy field was being defaulted
// in older versions. New versions stop defauting the field and drop on read, but for compatibility reasons we still accept the field. // in older versions. New versions stop defaulting the field and drop on read, but for compatibility reasons we still accept the field.
func Test_ExternalNameServiceDropsInternalTrafficPolicy(t *testing.T) { func Test_ExternalNameServiceDropsInternalTrafficPolicy(t *testing.T) {
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd()) server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
defer server.TearDownFn() defer server.TearDownFn()
@@ -120,7 +120,7 @@ func Test_ExternalNameServiceDropsInternalTrafficPolicy(t *testing.T) {
// Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy tests that converting a Service to Type=ExternalName // Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy tests that converting a Service to Type=ExternalName
// results in the internalTrafficPolicy field being dropped.This test exists due to historic reasons where the internalTrafficPolicy // results in the internalTrafficPolicy field being dropped.This test exists due to historic reasons where the internalTrafficPolicy
// field was being defaulted in older versions. New versions stop defauting the field and drop on read, but for compatibility reasons // field was being defaulted in older versions. New versions stop defaulting the field and drop on read, but for compatibility reasons
// we still accept the field. // we still accept the field.
func Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy(t *testing.T) { func Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy(t *testing.T) {
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd()) server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
@@ -164,7 +164,7 @@ func Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy(t *testing.T
service, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), newService, metav1.UpdateOptions{}) service, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), newService, metav1.UpdateOptions{})
if err != nil { if err != nil {
t.Fatalf("error getting service: %v", err) t.Fatalf("error updating service: %v", err)
} }
if service.Spec.InternalTrafficPolicy != nil { if service.Spec.InternalTrafficPolicy != nil {
@@ -180,3 +180,87 @@ func Test_ConvertingToExternalNameServiceDropsInternalTrafficPolicy(t *testing.T
t.Errorf("service internalTrafficPolicy should be droppped but is set: %v", service.Spec.InternalTrafficPolicy) t.Errorf("service internalTrafficPolicy should be droppped but is set: %v", service.Spec.InternalTrafficPolicy)
} }
} }
// Test_RemovingExternalIPsFromClusterIPServiceDropsExternalTrafficPolicy tests that removing externalIPs from a
// ClusterIP Service results in the externalTrafficPolicy field being dropped.
func Test_RemovingExternalIPsFromClusterIPServiceDropsExternalTrafficPolicy(t *testing.T) {
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
defer server.TearDownFn()
client, err := clientset.NewForConfig(server.ClientConfig)
if err != nil {
t.Fatalf("Error creating clientset: %v", err)
}
ns := framework.CreateNamespaceOrDie(client, "test-removing-external-ips-drops-external-traffic-policy", t)
defer framework.DeleteNamespaceOrDie(client, ns, t)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-123",
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeClusterIP,
Ports: []corev1.ServicePort{{
Port: int32(80),
}},
Selector: map[string]string{
"foo": "bar",
},
ExternalIPs: []string{"1.1.1.1"},
},
}
service, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Error creating test service: %v", err)
}
if service.Spec.ExternalTrafficPolicy != corev1.ServiceExternalTrafficPolicyCluster {
t.Error("service externalTrafficPolicy was not set for clusterIP Service with externalIPs")
}
// externalTrafficPolicy should be dropped after removing externalIPs.
newService := service.DeepCopy()
newService.Spec.ExternalIPs = []string{}
service, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), newService, metav1.UpdateOptions{})
if err != nil {
t.Fatalf("error updating service: %v", err)
}
if service.Spec.ExternalTrafficPolicy != "" {
t.Errorf("service externalTrafficPolicy should be droppped but is set: %v", service.Spec.ExternalTrafficPolicy)
}
service, err = client.CoreV1().Services(ns.Name).Get(context.TODO(), service.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("error getting service: %v", err)
}
if service.Spec.ExternalTrafficPolicy != "" {
t.Errorf("service externalTrafficPolicy should be droppped but is set: %v", service.Spec.ExternalTrafficPolicy)
}
// externalTrafficPolicy should be set after adding externalIPs again.
newService = service.DeepCopy()
newService.Spec.ExternalIPs = []string{"1.1.1.1"}
service, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), newService, metav1.UpdateOptions{})
if err != nil {
t.Fatalf("error updating service: %v", err)
}
if service.Spec.ExternalTrafficPolicy != corev1.ServiceExternalTrafficPolicyCluster {
t.Error("service externalTrafficPolicy was not set for clusterIP Service with externalIPs")
}
service, err = client.CoreV1().Services(ns.Name).Get(context.TODO(), service.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("error getting service: %v", err)
}
if service.Spec.ExternalTrafficPolicy != corev1.ServiceExternalTrafficPolicyCluster {
t.Error("service externalTrafficPolicy was not set for clusterIP Service with externalIPs")
}
}