mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #102412 from andrewsykim/kill-service-topology
Remove deprecated alpha Service topologyKeys field
This commit is contained in:
commit
7ed2ed1b45
@ -160,7 +160,6 @@ API rule violation: list_type_missing,k8s.io/api/core/v1,ServiceAccount,ImagePul
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,ServiceAccount,Secrets
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,ServiceSpec,ExternalIPs
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,ServiceSpec,LoadBalancerSourceRanges
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,ServiceSpec,TopologyKeys
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,TopologySelectorLabelRequirement,Values
|
||||
API rule violation: list_type_missing,k8s.io/api/core/v1,TopologySelectorTerm,MatchLabelExpressions
|
||||
API rule violation: list_type_missing,k8s.io/api/extensions/v1beta1,DaemonSetStatus,Conditions
|
||||
|
7
api/openapi-spec/swagger.json
generated
7
api/openapi-spec/swagger.json
generated
@ -9373,13 +9373,6 @@
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.SessionAffinityConfig",
|
||||
"description": "sessionAffinityConfig contains the configurations of session affinity."
|
||||
},
|
||||
"topologyKeys": {
|
||||
"description": "topologyKeys is a preference-order list of topology keys which implementations of services should use to preferentially sort endpoints when accessing this Service, it can not be used at the same time as externalTrafficPolicy=Local. Topology keys must be valid label keys and at most 16 keys may be specified. Endpoints are chosen based on the first topology key with available backends. If this field is specified and all entries have no backends that match the topology of the client, the service has no backends for that client and connections should fail. The special value \"*\" may be used to mean \"any topology\". This catch-all value, if used, only makes sense as the last value in the list. If this is not specified or empty, no topology constraints will be applied. This field is alpha-level and is only honored by servers that enable the ServiceTopology feature. This field is deprecated and will be removed in a future version.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"type": {
|
||||
"description": "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. \"ExternalName\" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types",
|
||||
"type": "string"
|
||||
|
@ -750,7 +750,7 @@ func (s *ProxyServer) Run() error {
|
||||
// functions must configure their shared informer event handlers first.
|
||||
informerFactory.Start(wait.NeverStop)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) || utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) {
|
||||
// Make an informer that selects for our nodename.
|
||||
currentNodeInformerFactory := informers.NewSharedInformerFactoryWithOptions(s.Client, s.ConfigSyncPeriod,
|
||||
informers.WithTweakListOptions(func(options *metav1.ListOptions) {
|
||||
|
@ -3560,11 +3560,6 @@ type LoadBalancerIngress struct {
|
||||
Ports []PortStatus
|
||||
}
|
||||
|
||||
const (
|
||||
// MaxServiceTopologyKeys is the largest number of topology keys allowed on a service
|
||||
MaxServiceTopologyKeys = 16
|
||||
)
|
||||
|
||||
// IPFamily represents the IP Family (IPv4 or IPv6). This type is used
|
||||
// to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
|
||||
type IPFamily string
|
||||
@ -3732,23 +3727,6 @@ type ServiceSpec struct {
|
||||
// +optional
|
||||
PublishNotReadyAddresses bool
|
||||
|
||||
// topologyKeys is a preference-order list of topology keys which
|
||||
// implementations of services should use to preferentially sort endpoints
|
||||
// when accessing this Service, it can not be used at the same time as
|
||||
// externalTrafficPolicy=Local.
|
||||
// Topology keys must be valid label keys and at most 16 keys may be specified.
|
||||
// Endpoints are chosen based on the first topology key with available backends.
|
||||
// If this field is specified and all entries have no backends that match
|
||||
// the topology of the client, the service has no backends for that client
|
||||
// and connections should fail.
|
||||
// The special value "*" may be used to mean "any topology". This catch-all
|
||||
// value, if used, only makes sense as the last value in the list.
|
||||
// If this is not specified or empty, no topology constraints will be applied.
|
||||
// This field is alpha-level and is only honored by servers that enable the ServiceTopology feature.
|
||||
// This field is deprecated and will be removed in a future version.
|
||||
// +optional
|
||||
TopologyKeys []string
|
||||
|
||||
// allocateLoadBalancerNodePorts defines if NodePorts will be automatically
|
||||
// allocated for services with type LoadBalancer. Default is "true". It may be
|
||||
// set to "false" if the cluster load-balancer does not rely on NodePorts.
|
||||
|
2
pkg/apis/core/v1/zz_generated.conversion.go
generated
2
pkg/apis/core/v1/zz_generated.conversion.go
generated
@ -7599,7 +7599,6 @@ func autoConvert_v1_ServiceSpec_To_core_ServiceSpec(in *v1.ServiceSpec, out *cor
|
||||
out.HealthCheckNodePort = in.HealthCheckNodePort
|
||||
out.PublishNotReadyAddresses = in.PublishNotReadyAddresses
|
||||
out.SessionAffinityConfig = (*core.SessionAffinityConfig)(unsafe.Pointer(in.SessionAffinityConfig))
|
||||
out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys))
|
||||
out.IPFamilies = *(*[]core.IPFamily)(unsafe.Pointer(&in.IPFamilies))
|
||||
out.IPFamilyPolicy = (*core.IPFamilyPolicyType)(unsafe.Pointer(in.IPFamilyPolicy))
|
||||
out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts))
|
||||
@ -7630,7 +7629,6 @@ func autoConvert_core_ServiceSpec_To_v1_ServiceSpec(in *core.ServiceSpec, out *v
|
||||
out.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyType(in.ExternalTrafficPolicy)
|
||||
out.HealthCheckNodePort = in.HealthCheckNodePort
|
||||
out.PublishNotReadyAddresses = in.PublishNotReadyAddresses
|
||||
out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys))
|
||||
out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts))
|
||||
out.LoadBalancerClass = (*string)(unsafe.Pointer(in.LoadBalancerClass))
|
||||
out.InternalTrafficPolicy = (*v1.ServiceInternalTrafficPolicyType)(unsafe.Pointer(in.InternalTrafficPolicy))
|
||||
|
@ -4327,35 +4327,6 @@ func ValidateService(service *core.Service) field.ErrorList {
|
||||
ports[key] = true
|
||||
}
|
||||
|
||||
// Validate TopologyKeys
|
||||
if len(service.Spec.TopologyKeys) > 0 {
|
||||
topoPath := specPath.Child("topologyKeys")
|
||||
// topologyKeys is mutually exclusive with 'externalTrafficPolicy=Local'
|
||||
if service.Spec.ExternalTrafficPolicy == core.ServiceExternalTrafficPolicyTypeLocal {
|
||||
allErrs = append(allErrs, field.Forbidden(topoPath, "may not be specified when `externalTrafficPolicy=Local`"))
|
||||
}
|
||||
if len(service.Spec.TopologyKeys) > core.MaxServiceTopologyKeys {
|
||||
allErrs = append(allErrs, field.TooMany(topoPath, len(service.Spec.TopologyKeys), core.MaxServiceTopologyKeys))
|
||||
}
|
||||
topoKeys := sets.NewString()
|
||||
for i, key := range service.Spec.TopologyKeys {
|
||||
keyPath := topoPath.Index(i)
|
||||
if topoKeys.Has(key) {
|
||||
allErrs = append(allErrs, field.Duplicate(keyPath, key))
|
||||
}
|
||||
topoKeys.Insert(key)
|
||||
// "Any" must be the last value specified
|
||||
if key == v1.TopologyKeyAny && i != len(service.Spec.TopologyKeys)-1 {
|
||||
allErrs = append(allErrs, field.Invalid(keyPath, key, `"*" must be the last value specified`))
|
||||
}
|
||||
if key != v1.TopologyKeyAny {
|
||||
for _, msg := range validation.IsQualifiedName(key) {
|
||||
allErrs = append(allErrs, field.Invalid(keyPath, service.Spec.TopologyKeys, msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate SourceRange field and annotation
|
||||
_, ok := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
|
||||
if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {
|
||||
|
@ -18,7 +18,6 @@ package validation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -10253,8 +10252,6 @@ func TestValidatePodEphemeralContainersUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidateServiceCreate(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceTopology, true)()
|
||||
|
||||
requireDualStack := core.IPFamilyPolicyRequireDualStack
|
||||
singleStack := core.IPFamilyPolicySingleStack
|
||||
preferDualStack := core.IPFamilyPolicyPreferDualStack
|
||||
@ -11315,67 +11312,6 @@ func TestValidateServiceCreate(t *testing.T) {
|
||||
numErrs: 0,
|
||||
},
|
||||
|
||||
/* toplogy keys */
|
||||
{
|
||||
name: "valid topology keys",
|
||||
tweakSvc: func(s *core.Service) {
|
||||
s.Spec.TopologyKeys = []string{
|
||||
"kubernetes.io/hostname",
|
||||
"topology.kubernetes.io/zone",
|
||||
"topology.kubernetes.io/region",
|
||||
v1.TopologyKeyAny,
|
||||
}
|
||||
},
|
||||
numErrs: 0,
|
||||
},
|
||||
{
|
||||
name: "invalid topology key",
|
||||
tweakSvc: func(s *core.Service) {
|
||||
s.Spec.TopologyKeys = []string{"NoUppercaseOrSpecialCharsLike=Equals"}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "too many topology keys",
|
||||
tweakSvc: func(s *core.Service) {
|
||||
for i := 0; i < core.MaxServiceTopologyKeys+1; i++ {
|
||||
s.Spec.TopologyKeys = append(s.Spec.TopologyKeys, fmt.Sprintf("topologykey-%d", i))
|
||||
}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: `"Any" was not the last key`,
|
||||
tweakSvc: func(s *core.Service) {
|
||||
s.Spec.TopologyKeys = []string{
|
||||
"kubernetes.io/hostname",
|
||||
v1.TopologyKeyAny,
|
||||
"topology.kubernetes.io/zone",
|
||||
}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: `duplicate topology key`,
|
||||
tweakSvc: func(s *core.Service) {
|
||||
s.Spec.TopologyKeys = []string{
|
||||
"kubernetes.io/hostname",
|
||||
"kubernetes.io/hostname",
|
||||
"topology.kubernetes.io/zone",
|
||||
}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: `use topology keys with externalTrafficPolicy=Local`,
|
||||
tweakSvc: func(s *core.Service) {
|
||||
s.Spec.ExternalTrafficPolicy = "Local"
|
||||
s.Spec.TopologyKeys = []string{
|
||||
"kubernetes.io/hostname",
|
||||
}
|
||||
},
|
||||
numErrs: 1,
|
||||
},
|
||||
{
|
||||
name: `valid appProtocol`,
|
||||
tweakSvc: func(s *core.Service) {
|
||||
|
5
pkg/apis/core/zz_generated.deepcopy.go
generated
5
pkg/apis/core/zz_generated.deepcopy.go
generated
@ -5292,11 +5292,6 @@ func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TopologyKeys != nil {
|
||||
in, out := &in.TopologyKeys, &out.TopologyKeys
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.AllocateLoadBalancerNodePorts != nil {
|
||||
in, out := &in.AllocateLoadBalancerNodePorts, &out.AllocateLoadBalancerNodePorts
|
||||
*out = new(bool)
|
||||
|
@ -513,12 +513,6 @@ const (
|
||||
// DaemonSets allow workloads to maintain availability during update per node
|
||||
DaemonSetUpdateSurge featuregate.Feature = "DaemonSetUpdateSurge"
|
||||
|
||||
// owner: @m1093782566
|
||||
// alpha: v1.17
|
||||
//
|
||||
// Enables topology aware service routing
|
||||
ServiceTopology featuregate.Feature = "ServiceTopology"
|
||||
|
||||
// owner: @robscott
|
||||
// kep: http://kep.k8s.io/1507
|
||||
// alpha: v1.18
|
||||
@ -841,7 +835,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
PodDisruptionBudget: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
|
||||
CronJobControllerV2: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
|
||||
DaemonSetUpdateSurge: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
|
||||
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ServiceAppProtocol: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22
|
||||
ImmutableEphemeralVolumes: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
|
||||
HugePageStorageMediumSize: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
@ -54,7 +54,6 @@ type BaseServiceInfo struct {
|
||||
nodeLocalExternal bool
|
||||
nodeLocalInternal bool
|
||||
internalTrafficPolicy *v1.ServiceInternalTrafficPolicyType
|
||||
topologyKeys []string
|
||||
hintsAnnotation string
|
||||
}
|
||||
|
||||
@ -134,11 +133,6 @@ func (info *BaseServiceInfo) InternalTrafficPolicy() *v1.ServiceInternalTrafficP
|
||||
return info.internalTrafficPolicy
|
||||
}
|
||||
|
||||
// TopologyKeys is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) TopologyKeys() []string {
|
||||
return info.topologyKeys
|
||||
}
|
||||
|
||||
// HintsAnnotation is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) HintsAnnotation() string {
|
||||
return info.hintsAnnotation
|
||||
@ -170,7 +164,6 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic
|
||||
nodeLocalExternal: nodeLocalExternal,
|
||||
nodeLocalInternal: nodeLocalInternal,
|
||||
internalTrafficPolicy: service.Spec.InternalTrafficPolicy,
|
||||
topologyKeys: service.Spec.TopologyKeys,
|
||||
hintsAnnotation: service.Annotations[v1.AnnotationTopologyAwareHints],
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,6 @@ func FilterEndpoints(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[s
|
||||
return endpoints
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) {
|
||||
return deprecatedTopologyFilter(nodeLabels, svcInfo.TopologyKeys(), endpoints)
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) && svcInfo.NodeLocalInternal() {
|
||||
return filterEndpointsInternalTrafficPolicy(svcInfo.InternalTrafficPolicy(), endpoints)
|
||||
}
|
||||
@ -89,67 +85,6 @@ func filterEndpointsWithHints(endpoints []Endpoint, hintsAnnotation string, node
|
||||
return filteredEndpoints
|
||||
}
|
||||
|
||||
// deprecatedTopologyFilter returns the appropriate endpoints based on the
|
||||
// cluster topology. This will be removed in an upcoming release along with the
|
||||
// ServiceTopology feature gate.
|
||||
//
|
||||
// This uses the current node's labels, which contain topology information, and
|
||||
// the required topologyKeys to find appropriate endpoints. If both the endpoint's
|
||||
// topology and the current node have matching values for topologyKeys[0], the
|
||||
// endpoint will be chosen. If no endpoints are chosen, toplogyKeys[1] will be
|
||||
// considered, and so on. If either the node or the endpoint do not have values
|
||||
// for a key, it is considered to not match.
|
||||
//
|
||||
// If topologyKeys is specified, but no endpoints are chosen for any key, the
|
||||
// service has no viable endpoints for clients on this node, and connections
|
||||
// should fail.
|
||||
//
|
||||
// The special key "*" may be used as the last entry in topologyKeys to indicate
|
||||
// "any endpoint" is acceptable.
|
||||
//
|
||||
// If topologyKeys is not specified or empty, no topology constraints will be
|
||||
// applied and this will return all endpoints.
|
||||
func deprecatedTopologyFilter(nodeLabels map[string]string, topologyKeys []string, endpoints []Endpoint) []Endpoint {
|
||||
// Do not filter endpoints if service has no topology keys.
|
||||
if len(topologyKeys) == 0 {
|
||||
return endpoints
|
||||
}
|
||||
|
||||
filteredEndpoints := []Endpoint{}
|
||||
|
||||
if len(nodeLabels) == 0 {
|
||||
if topologyKeys[len(topologyKeys)-1] == v1.TopologyKeyAny {
|
||||
// edge case: include all endpoints if topology key "Any" specified
|
||||
// when we cannot determine current node's topology.
|
||||
return endpoints
|
||||
}
|
||||
// edge case: do not include any endpoints if topology key "Any" is
|
||||
// not specified when we cannot determine current node's topology.
|
||||
return filteredEndpoints
|
||||
}
|
||||
|
||||
for _, key := range topologyKeys {
|
||||
if key == v1.TopologyKeyAny {
|
||||
return endpoints
|
||||
}
|
||||
topologyValue, found := nodeLabels[key]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ep := range endpoints {
|
||||
topology := ep.GetTopology()
|
||||
if value, found := topology[key]; found && value == topologyValue {
|
||||
filteredEndpoints = append(filteredEndpoints, ep)
|
||||
}
|
||||
}
|
||||
if len(filteredEndpoints) > 0 {
|
||||
return filteredEndpoints
|
||||
}
|
||||
}
|
||||
return filteredEndpoints
|
||||
}
|
||||
|
||||
// filterEndpointsInternalTrafficPolicy returns the node local endpoints based
|
||||
// on configured InternalTrafficPolicy.
|
||||
//
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
@ -34,14 +33,13 @@ func TestFilterEndpoints(t *testing.T) {
|
||||
zoneHints sets.String
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
epsProxyingEnabled bool
|
||||
serviceTopologyEnabled bool
|
||||
hintsEnabled bool
|
||||
nodeLabels map[string]string
|
||||
serviceInfo ServicePort
|
||||
endpoints []endpoint
|
||||
expectedEndpoints []endpoint
|
||||
name string
|
||||
epsProxyingEnabled bool
|
||||
hintsEnabled bool
|
||||
nodeLabels map[string]string
|
||||
serviceInfo ServicePort
|
||||
endpoints []endpoint
|
||||
expectedEndpoints []endpoint
|
||||
}{{
|
||||
name: "hints + eps proxying enabled, hints annotation == auto",
|
||||
hintsEnabled: true,
|
||||
@ -148,25 +146,6 @@ func TestFilterEndpoints(t *testing.T) {
|
||||
{ip: "10.1.2.5", zoneHints: sets.NewString("zone-c")},
|
||||
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||
},
|
||||
}, {
|
||||
name: "all gates enabled, serviceTopology gate takes precedence and hints are ignored",
|
||||
hintsEnabled: true,
|
||||
epsProxyingEnabled: true,
|
||||
serviceTopologyEnabled: true,
|
||||
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
||||
serviceInfo: &BaseServiceInfo{nodeLocalExternal: true},
|
||||
endpoints: []endpoint{
|
||||
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||
{ip: "10.1.2.4", zoneHints: sets.NewString("zone-b")},
|
||||
{ip: "10.1.2.5", zoneHints: sets.NewString("zone-c")},
|
||||
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||
},
|
||||
expectedEndpoints: []endpoint{
|
||||
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||
{ip: "10.1.2.4", zoneHints: sets.NewString("zone-b")},
|
||||
{ip: "10.1.2.5", zoneHints: sets.NewString("zone-c")},
|
||||
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||
},
|
||||
}}
|
||||
|
||||
endpointsToStringArray := func(endpoints []Endpoint) []string {
|
||||
@ -180,7 +159,6 @@ func TestFilterEndpoints(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceProxying, tc.epsProxyingEnabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceTopology, tc.serviceTopologyEnabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, tc.hintsEnabled)()
|
||||
|
||||
endpoints := []Endpoint{}
|
||||
@ -357,459 +335,6 @@ func Test_filterEndpointsWithHints(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_deprecatedTopologyFilter(t *testing.T) {
|
||||
type endpoint struct {
|
||||
Endpoint string
|
||||
NodeName types.NodeName
|
||||
}
|
||||
testCases := []struct {
|
||||
Name string
|
||||
nodeLabels map[types.NodeName]map[string]string
|
||||
endpoints []endpoint
|
||||
currentNodeName types.NodeName
|
||||
topologyKeys []string
|
||||
expected []endpoint
|
||||
}{
|
||||
{
|
||||
// Case[0]: no topology key and endpoints at all = 0 endpoints
|
||||
Name: "no topology key and endpoints",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "10.0.0.1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
}},
|
||||
endpoints: []endpoint{},
|
||||
currentNodeName: "testNode1",
|
||||
topologyKeys: nil,
|
||||
expected: []endpoint{},
|
||||
},
|
||||
{
|
||||
// Case[1]: no topology key, 2 nodes each with 2 endpoints = 4
|
||||
// endpoints
|
||||
Name: "no topology key but have endpoints",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
currentNodeName: "testNode1",
|
||||
topologyKeys: nil,
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[2]: 1 topology key (hostname), 2 nodes each with 2 endpoints
|
||||
// 1 match = 2 endpoints
|
||||
Name: "one topology key with one node matched",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
currentNodeName: "testNode1",
|
||||
topologyKeys: []string{"kubernetes.io/hostname"},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[3]: 1 topology key (hostname), 2 nodes each with 2 endpoints
|
||||
// no match = 0 endpoints
|
||||
Name: "one topology key without node matched",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
currentNodeName: "testNode3",
|
||||
topologyKeys: []string{"kubernetes.io/hostname"},
|
||||
expected: []endpoint{},
|
||||
},
|
||||
{
|
||||
// Case[4]: 1 topology key (zone), 2 nodes in zone a, 2 nodes in
|
||||
// zone b, each with 2 endpoints = 4 endpoints
|
||||
Name: "one topology key with multiple nodes matched",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode4": {
|
||||
"kubernetes.io/hostname": "testNode4",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
currentNodeName: "testNode2",
|
||||
topologyKeys: []string{"topology.kubernetes.io/zone"},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[5]: 2 topology keys (hostname, zone), 2 nodes each with 2
|
||||
// endpoints, 1 hostname match = 2 endpoints (2nd key ignored)
|
||||
Name: "early match in multiple topology keys",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode4": {
|
||||
"kubernetes.io/hostname": "testNode4",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
currentNodeName: "testNode2",
|
||||
topologyKeys: []string{"kubernetes.io/hostname"},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[6]: 2 topology keys (hostname, zone), 2 nodes in zone a, 2
|
||||
// nodes in zone b, each with 2 endpoints, no hostname match, 1 zone
|
||||
// match = 4 endpoints
|
||||
Name: "later match in multiple topology keys",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode4": {
|
||||
"kubernetes.io/hostname": "testNode4",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode5": {
|
||||
"kubernetes.io/hostname": "testNode5",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
currentNodeName: "testNode5",
|
||||
topologyKeys: []string{"kubernetes.io/hostname", "topology.kubernetes.io/zone"},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[7]: 2 topology keys (hostname, zone), 2 nodes in zone a, 2
|
||||
// nodes in zone b, each with 2 endpoints, no hostname match, no zone
|
||||
// match = 0 endpoints
|
||||
Name: "multiple topology keys without node matched",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode4": {
|
||||
"kubernetes.io/hostname": "testNode4",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode5": {
|
||||
"kubernetes.io/hostname": "testNode5",
|
||||
"topology.kubernetes.io/zone": "90003",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
currentNodeName: "testNode5",
|
||||
topologyKeys: []string{"kubernetes.io/hostname", "topology.kubernetes.io/zone"},
|
||||
expected: []endpoint{},
|
||||
},
|
||||
{
|
||||
// Case[8]: 2 topology keys (hostname, "*"), 2 nodes each with 2
|
||||
// endpoints, 1 match hostname = 2 endpoints
|
||||
Name: "multiple topology keys matched node when 'Any' key ignored",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
currentNodeName: "testNode1",
|
||||
topologyKeys: []string{"kubernetes.io/hostname", v1.TopologyKeyAny},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[9]: 2 topology keys (hostname, "*"), 2 nodes each with 2
|
||||
// endpoints, no hostname match, catch-all ("*") matched with 4
|
||||
// endpoints
|
||||
Name: "two topology keys matched node with 'Any' key",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
currentNodeName: "testNode3",
|
||||
topologyKeys: []string{"kubernetes.io/hostname", v1.TopologyKeyAny},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Case[10]: 3 topology keys (hostname, zone, "*"), 2 nodes in zone a,
|
||||
// 2 nodes in zone b, each with 2 endpoints, no hostname match, no
|
||||
// zone, catch-all ("*") matched with 8 endpoints
|
||||
Name: "multiple topology keys matched node with 'Any' key",
|
||||
nodeLabels: map[types.NodeName]map[string]string{
|
||||
"testNode1": {
|
||||
"kubernetes.io/hostname": "testNode1",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode2": {
|
||||
"kubernetes.io/hostname": "testNode2",
|
||||
"topology.kubernetes.io/zone": "90001",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode3": {
|
||||
"kubernetes.io/hostname": "testNode3",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode4": {
|
||||
"kubernetes.io/hostname": "testNode4",
|
||||
"topology.kubernetes.io/zone": "90002",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
"testNode5": {
|
||||
"kubernetes.io/hostname": "testNode5",
|
||||
"topology.kubernetes.io/zone": "90003",
|
||||
"topology.kubernetes.io/region": "cd",
|
||||
},
|
||||
},
|
||||
endpoints: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
currentNodeName: "testNode5",
|
||||
topologyKeys: []string{"kubernetes.io/hostname", "topology.kubernetes.io/zone", v1.TopologyKeyAny},
|
||||
expected: []endpoint{
|
||||
{Endpoint: "1.1.1.1:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.1.2:11", NodeName: "testNode1"},
|
||||
{Endpoint: "1.1.2.1:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.2.2:11", NodeName: "testNode2"},
|
||||
{Endpoint: "1.1.3.1:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.3.2:11", NodeName: "testNode3"},
|
||||
{Endpoint: "1.1.4.1:11", NodeName: "testNode4"},
|
||||
{Endpoint: "1.1.4.2:11", NodeName: "testNode4"},
|
||||
},
|
||||
},
|
||||
}
|
||||
endpointsToStringArray := func(endpoints []endpoint) []string {
|
||||
result := make([]string, 0, len(endpoints))
|
||||
for _, ep := range endpoints {
|
||||
result = append(result, ep.Endpoint)
|
||||
}
|
||||
return result
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
m := make(map[Endpoint]endpoint)
|
||||
endpoints := []Endpoint{}
|
||||
for _, ep := range tc.endpoints {
|
||||
var e Endpoint = &BaseEndpointInfo{Endpoint: ep.Endpoint, Topology: tc.nodeLabels[ep.NodeName]}
|
||||
m[e] = ep
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
currentNodeLabels := tc.nodeLabels[tc.currentNodeName]
|
||||
filteredEndpoint := []endpoint{}
|
||||
for _, ep := range deprecatedTopologyFilter(currentNodeLabels, tc.topologyKeys, endpoints) {
|
||||
filteredEndpoint = append(filteredEndpoint, m[ep])
|
||||
}
|
||||
if !reflect.DeepEqual(filteredEndpoint, tc.expected) {
|
||||
t.Errorf("expected %v, got %v", endpointsToStringArray(tc.expected), endpointsToStringArray(filteredEndpoint))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_filterEndpointsInternalTrafficPolicy(t *testing.T) {
|
||||
cluster := v1.ServiceInternalTrafficPolicyCluster
|
||||
local := v1.ServiceInternalTrafficPolicyLocal
|
||||
|
@ -90,8 +90,6 @@ type ServicePort interface {
|
||||
NodeLocalInternal() bool
|
||||
// InternalTrafficPolicy returns service InternalTrafficPolicy
|
||||
InternalTrafficPolicy() *v1.ServiceInternalTrafficPolicyType
|
||||
// TopologyKeys returns service TopologyKeys as a string array.
|
||||
TopologyKeys() []string
|
||||
// HintsAnnotation returns the value of the v1.AnnotationTopologyAwareHints annotation.
|
||||
HintsAnnotation() string
|
||||
}
|
||||
|
@ -173,11 +173,6 @@ func dropServiceDisabledFields(newSvc *api.Service, oldSvc *api.Service) {
|
||||
}
|
||||
}
|
||||
|
||||
// Drop TopologyKeys if ServiceTopology is not enabled
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) && !topologyKeysInUse(oldSvc) {
|
||||
newSvc.Spec.TopologyKeys = nil
|
||||
}
|
||||
|
||||
// Clear AllocateLoadBalancerNodePorts if ServiceLBNodePortControl is not enabled
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
|
||||
if !allocateLoadBalancerNodePortsInUse(oldSvc) {
|
||||
@ -232,14 +227,6 @@ func serviceDualStackFieldsInUse(svc *api.Service) bool {
|
||||
return ipFamilyPolicyInUse || ipFamiliesInUse || ClusterIPsInUse
|
||||
}
|
||||
|
||||
// returns true if svc.Spec.TopologyKeys field is in use
|
||||
func topologyKeysInUse(svc *api.Service) bool {
|
||||
if svc == nil {
|
||||
return false
|
||||
}
|
||||
return len(svc.Spec.TopologyKeys) > 0
|
||||
}
|
||||
|
||||
// returns true when the svc.Status.Conditions field is in use.
|
||||
func serviceConditionsInUse(svc *api.Service) bool {
|
||||
if svc == nil {
|
||||
|
1809
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
1809
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
File diff suppressed because it is too large
Load Diff
@ -4988,23 +4988,6 @@ message ServiceSpec {
|
||||
// +optional
|
||||
optional SessionAffinityConfig sessionAffinityConfig = 14;
|
||||
|
||||
// topologyKeys is a preference-order list of topology keys which
|
||||
// implementations of services should use to preferentially sort endpoints
|
||||
// when accessing this Service, it can not be used at the same time as
|
||||
// externalTrafficPolicy=Local.
|
||||
// Topology keys must be valid label keys and at most 16 keys may be specified.
|
||||
// Endpoints are chosen based on the first topology key with available backends.
|
||||
// If this field is specified and all entries have no backends that match
|
||||
// the topology of the client, the service has no backends for that client
|
||||
// and connections should fail.
|
||||
// The special value "*" may be used to mean "any topology". This catch-all
|
||||
// value, if used, only makes sense as the last value in the list.
|
||||
// If this is not specified or empty, no topology constraints will be applied.
|
||||
// This field is alpha-level and is only honored by servers that enable the ServiceTopology feature.
|
||||
// This field is deprecated and will be removed in a future version.
|
||||
// +optional
|
||||
repeated string topologyKeys = 16;
|
||||
|
||||
// IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this
|
||||
// service, and is gated by the "IPv6DualStack" feature gate. This field
|
||||
// is usually assigned automatically based on cluster configuration and the
|
||||
|
@ -30,8 +30,6 @@ const (
|
||||
NamespaceAll string = ""
|
||||
// NamespaceNodeLease is the namespace where we place node lease objects (used for node heartbeats)
|
||||
NamespaceNodeLease string = "kube-node-lease"
|
||||
// TopologyKeyAny is the service topology key that matches any node
|
||||
TopologyKeyAny string = "*"
|
||||
)
|
||||
|
||||
// Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||
@ -4039,11 +4037,6 @@ type LoadBalancerIngress struct {
|
||||
Ports []PortStatus `json:"ports,omitempty" protobuf:"bytes,4,rep,name=ports"`
|
||||
}
|
||||
|
||||
const (
|
||||
// MaxServiceTopologyKeys is the largest number of topology keys allowed on a service
|
||||
MaxServiceTopologyKeys = 16
|
||||
)
|
||||
|
||||
// IPFamily represents the IP Family (IPv4 or IPv6). This type is used
|
||||
// to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
|
||||
type IPFamily string
|
||||
@ -4240,22 +4233,8 @@ type ServiceSpec struct {
|
||||
// +optional
|
||||
SessionAffinityConfig *SessionAffinityConfig `json:"sessionAffinityConfig,omitempty" protobuf:"bytes,14,opt,name=sessionAffinityConfig"`
|
||||
|
||||
// topologyKeys is a preference-order list of topology keys which
|
||||
// implementations of services should use to preferentially sort endpoints
|
||||
// when accessing this Service, it can not be used at the same time as
|
||||
// externalTrafficPolicy=Local.
|
||||
// Topology keys must be valid label keys and at most 16 keys may be specified.
|
||||
// Endpoints are chosen based on the first topology key with available backends.
|
||||
// If this field is specified and all entries have no backends that match
|
||||
// the topology of the client, the service has no backends for that client
|
||||
// and connections should fail.
|
||||
// The special value "*" may be used to mean "any topology". This catch-all
|
||||
// value, if used, only makes sense as the last value in the list.
|
||||
// If this is not specified or empty, no topology constraints will be applied.
|
||||
// This field is alpha-level and is only honored by servers that enable the ServiceTopology feature.
|
||||
// This field is deprecated and will be removed in a future version.
|
||||
// +optional
|
||||
TopologyKeys []string `json:"topologyKeys,omitempty" protobuf:"bytes,16,opt,name=topologyKeys"`
|
||||
// TopologyKeys is tombstoned to show why 16 is reserved protobuf tag.
|
||||
//TopologyKeys []string `json:"topologyKeys,omitempty" protobuf:"bytes,16,opt,name=topologyKeys"`
|
||||
|
||||
// IPFamily is tombstoned to show why 15 is a reserved protobuf tag.
|
||||
// IPFamily *IPFamily `json:"ipFamily,omitempty" protobuf:"bytes,15,opt,name=ipFamily,Configcasttype=IPFamily"`
|
||||
|
@ -2244,7 +2244,6 @@ var map_ServiceSpec = map[string]string{
|
||||
"healthCheckNodePort": "healthCheckNodePort specifies the healthcheck nodePort for the service. This only applies when type is set to LoadBalancer and externalTrafficPolicy is set to Local. If a value is specified, is in-range, and is not in use, it will be used. If not specified, a value will be automatically allocated. External systems (e.g. load-balancers) can use this port to determine if a given node holds endpoints for this service or not. If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type).",
|
||||
"publishNotReadyAddresses": "publishNotReadyAddresses indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready. The primary use case for setting this field is for a StatefulSet's Headless Service to propagate SRV DNS records for its Pods for the purpose of peer discovery. The Kubernetes controllers that generate Endpoints and EndpointSlice resources for Services interpret this to mean that all endpoints are considered \"ready\" even if the Pods themselves are not. Agents which consume only Kubernetes generated endpoints through the Endpoints or EndpointSlice resources can safely assume this behavior.",
|
||||
"sessionAffinityConfig": "sessionAffinityConfig contains the configurations of session affinity.",
|
||||
"topologyKeys": "topologyKeys is a preference-order list of topology keys which implementations of services should use to preferentially sort endpoints when accessing this Service, it can not be used at the same time as externalTrafficPolicy=Local. Topology keys must be valid label keys and at most 16 keys may be specified. Endpoints are chosen based on the first topology key with available backends. If this field is specified and all entries have no backends that match the topology of the client, the service has no backends for that client and connections should fail. The special value \"*\" may be used to mean \"any topology\". This catch-all value, if used, only makes sense as the last value in the list. If this is not specified or empty, no topology constraints will be applied. This field is alpha-level and is only honored by servers that enable the ServiceTopology feature. This field is deprecated and will be removed in a future version.",
|
||||
"ipFamilies": "IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service, and is gated by the \"IPv6DualStack\" feature gate. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are \"IPv4\" and \"IPv6\". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to \"headless\" services. This field will be wiped when updating a Service to type ExternalName.\n\nThis field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field.",
|
||||
"ipFamilyPolicy": "IPFamilyPolicy represents the dual-stack-ness requested or required by this Service, and is gated by the \"IPv6DualStack\" feature gate. If there is no value provided, then this field will be set to SingleStack. Services can be \"SingleStack\" (a single IP family), \"PreferDualStack\" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or \"RequireDualStack\" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName.",
|
||||
"allocateLoadBalancerNodePorts": "allocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is \"true\". It may be set to \"false\" if the cluster load-balancer does not rely on NodePorts. allocateLoadBalancerNodePorts may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. This field is alpha-level and is only honored by servers that enable the ServiceLBNodePortControl feature.",
|
||||
|
41
staging/src/k8s.io/api/core/v1/types_test.go
Normal file
41
staging/src/k8s.io/api/core/v1/types_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test_ServiceSpecRemovedFieldProtobufNumberReservation tests that the reserved protobuf field numbers
|
||||
// for removed fields are not re-used. DO NOT remove this test for any reason, this ensures that tombstoned
|
||||
// protobuf field numbers are not accidentally reused by other fields.
|
||||
func Test_ServiceSpecRemovedFieldProtobufNumberReservation(t *testing.T) {
|
||||
obj := reflect.ValueOf(ServiceSpec{}).Type()
|
||||
for i := 0; i < obj.NumField(); i++ {
|
||||
f := obj.Field(i)
|
||||
|
||||
protobufNum := strings.Split(f.Tag.Get("protobuf"), ",")[1]
|
||||
if protobufNum == "15" {
|
||||
t.Errorf("protobuf 15 in ServiceSpec is reserved for removed ipFamily field")
|
||||
}
|
||||
if protobufNum == "16" {
|
||||
t.Errorf("protobuf 16 in ServiceSpec is reserved for removed topologyKeys field")
|
||||
}
|
||||
}
|
||||
}
|
@ -5297,11 +5297,6 @@ func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) {
|
||||
*out = new(SessionAffinityConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.TopologyKeys != nil {
|
||||
in, out := &in.TopologyKeys, &out.TopologyKeys
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.IPFamilies != nil {
|
||||
in, out := &in.IPFamilies, &out.IPFamilies
|
||||
*out = make([]IPFamily, len(*in))
|
||||
|
@ -77,28 +77,25 @@
|
||||
"timeoutSeconds": 2072604405
|
||||
}
|
||||
},
|
||||
"topologyKeys": [
|
||||
"31"
|
||||
],
|
||||
"ipFamilies": [
|
||||
"斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ"
|
||||
"x"
|
||||
],
|
||||
"ipFamilyPolicy": "9ȫŚ",
|
||||
"ipFamilyPolicy": "%a鯿rŎǀ朲^苣f",
|
||||
"allocateLoadBalancerNodePorts": true,
|
||||
"loadBalancerClass": "32",
|
||||
"internalTrafficPolicy": ""
|
||||
"loadBalancerClass": "31",
|
||||
"internalTrafficPolicy": "hDrȮO励鹗"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {
|
||||
"ingress": [
|
||||
{
|
||||
"ip": "33",
|
||||
"hostname": "34",
|
||||
"ip": "32",
|
||||
"hostname": "33",
|
||||
"ports": [
|
||||
{
|
||||
"port": 684408190,
|
||||
"protocol": "ƈ斎AO6ĴC浔Ű",
|
||||
"error": "35"
|
||||
"port": 165528693,
|
||||
"protocol": "UɦOŖ",
|
||||
"error": "34"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -106,12 +103,12 @@
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"type": "36",
|
||||
"status": "ž(-譵",
|
||||
"observedGeneration": -8651056334266075769,
|
||||
"lastTransitionTime": "2404-01-10T11:35:42Z",
|
||||
"reason": "37",
|
||||
"message": "38"
|
||||
"type": "35",
|
||||
"status": "尷ȸd賑",
|
||||
"observedGeneration": 3519145202439908029,
|
||||
"lastTransitionTime": "2256-09-10T15:38:25Z",
|
||||
"reason": "36",
|
||||
"message": "37"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Binary file not shown.
@ -40,11 +40,11 @@ spec:
|
||||
externalName: "30"
|
||||
externalTrafficPolicy: ƏS$+½H牗洝尿
|
||||
healthCheckNodePort: -1965738697
|
||||
internalTrafficPolicy: ""
|
||||
internalTrafficPolicy: hDrȮO励鹗
|
||||
ipFamilies:
|
||||
- 斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ
|
||||
ipFamilyPolicy: 9ȫŚ
|
||||
loadBalancerClass: "32"
|
||||
- x
|
||||
ipFamilyPolicy: '%a鯿rŎǀ朲^苣f'
|
||||
loadBalancerClass: "31"
|
||||
loadBalancerIP: "28"
|
||||
loadBalancerSourceRanges:
|
||||
- "29"
|
||||
@ -62,22 +62,20 @@ spec:
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 2072604405
|
||||
topologyKeys:
|
||||
- "31"
|
||||
type: 鮽ort昍řČ扷5ƗǸƢ6/ʕVŚ(Ŀ
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2404-01-10T11:35:42Z"
|
||||
message: "38"
|
||||
observedGeneration: -8651056334266075769
|
||||
reason: "37"
|
||||
status: ž(-譵
|
||||
type: "36"
|
||||
- lastTransitionTime: "2256-09-10T15:38:25Z"
|
||||
message: "37"
|
||||
observedGeneration: 3519145202439908029
|
||||
reason: "36"
|
||||
status: 尷ȸd賑
|
||||
type: "35"
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- hostname: "34"
|
||||
ip: "33"
|
||||
- hostname: "33"
|
||||
ip: "32"
|
||||
ports:
|
||||
- error: "35"
|
||||
port: 684408190
|
||||
protocol: ƈ斎AO6ĴC浔Ű
|
||||
- error: "34"
|
||||
port: 165528693
|
||||
protocol: UɦOŖ
|
||||
|
112
staging/src/k8s.io/api/testdata/v1.20.0/core.v1.Service.after_roundtrip.json
vendored
Normal file
112
staging/src/k8s.io/api/testdata/v1.20.0/core.v1.Service.after_roundtrip.json
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "2",
|
||||
"generateName": "3",
|
||||
"namespace": "4",
|
||||
"selfLink": "5",
|
||||
"uid": "7",
|
||||
"resourceVersion": "11042405498087606203",
|
||||
"generation": 8071137005907523419,
|
||||
"creationTimestamp": null,
|
||||
"deletionGracePeriodSeconds": -4955867275792137171,
|
||||
"labels": {
|
||||
"7": "8"
|
||||
},
|
||||
"annotations": {
|
||||
"9": "10"
|
||||
},
|
||||
"ownerReferences": [
|
||||
{
|
||||
"apiVersion": "11",
|
||||
"kind": "12",
|
||||
"name": "13",
|
||||
"uid": "Dz廔ȇ{sŊƏp",
|
||||
"controller": false,
|
||||
"blockOwnerDeletion": true
|
||||
}
|
||||
],
|
||||
"finalizers": [
|
||||
"14"
|
||||
],
|
||||
"clusterName": "15",
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "16",
|
||||
"operation": "鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć]",
|
||||
"apiVersion": "17",
|
||||
"fieldsType": "18"
|
||||
}
|
||||
]
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "19",
|
||||
"protocol": "@Hr鯹)晿",
|
||||
"appProtocol": "20",
|
||||
"port": 202283346,
|
||||
"targetPort": "21",
|
||||
"nodePort": -474380055
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"22": "23"
|
||||
},
|
||||
"clusterIP": "24",
|
||||
"clusterIPs": [
|
||||
"25"
|
||||
],
|
||||
"type": "鮽ort昍řČ扷5ƗǸƢ6/ʕVŚ(Ŀ",
|
||||
"externalIPs": [
|
||||
"26"
|
||||
],
|
||||
"sessionAffinity": "甞谐颋DžS",
|
||||
"loadBalancerIP": "27",
|
||||
"loadBalancerSourceRanges": [
|
||||
"28"
|
||||
],
|
||||
"externalName": "29",
|
||||
"externalTrafficPolicy": "ƏS$+½H牗洝尿",
|
||||
"healthCheckNodePort": -1965738697,
|
||||
"publishNotReadyAddresses": true,
|
||||
"sessionAffinityConfig": {
|
||||
"clientIP": {
|
||||
"timeoutSeconds": 2072604405
|
||||
}
|
||||
},
|
||||
"ipFamilies": [
|
||||
"斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ"
|
||||
],
|
||||
"ipFamilyPolicy": "9ȫŚ",
|
||||
"allocateLoadBalancerNodePorts": true
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {
|
||||
"ingress": [
|
||||
{
|
||||
"ip": "31",
|
||||
"hostname": "32",
|
||||
"ports": [
|
||||
{
|
||||
"port": -907310967,
|
||||
"protocol": "喂ƈ斎AO6",
|
||||
"error": "33"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"type": "34",
|
||||
"status": "C",
|
||||
"observedGeneration": -2492120148461555858,
|
||||
"lastTransitionTime": "2392-12-09T15:37:55Z",
|
||||
"reason": "35",
|
||||
"message": "36"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Binary file not shown.
78
staging/src/k8s.io/api/testdata/v1.20.0/core.v1.Service.after_roundtrip.yaml
vendored
Normal file
78
staging/src/k8s.io/api/testdata/v1.20.0/core.v1.Service.after_roundtrip.yaml
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
"9": "10"
|
||||
clusterName: "15"
|
||||
creationTimestamp: null
|
||||
deletionGracePeriodSeconds: -4955867275792137171
|
||||
finalizers:
|
||||
- "14"
|
||||
generateName: "3"
|
||||
generation: 8071137005907523419
|
||||
labels:
|
||||
"7": "8"
|
||||
managedFields:
|
||||
- apiVersion: "17"
|
||||
fieldsType: "18"
|
||||
manager: "16"
|
||||
operation: 鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć]
|
||||
name: "2"
|
||||
namespace: "4"
|
||||
ownerReferences:
|
||||
- apiVersion: "11"
|
||||
blockOwnerDeletion: true
|
||||
controller: false
|
||||
kind: "12"
|
||||
name: "13"
|
||||
uid: Dz廔ȇ{sŊƏp
|
||||
resourceVersion: "11042405498087606203"
|
||||
selfLink: "5"
|
||||
uid: "7"
|
||||
spec:
|
||||
allocateLoadBalancerNodePorts: true
|
||||
clusterIP: "24"
|
||||
clusterIPs:
|
||||
- "25"
|
||||
externalIPs:
|
||||
- "26"
|
||||
externalName: "29"
|
||||
externalTrafficPolicy: ƏS$+½H牗洝尿
|
||||
healthCheckNodePort: -1965738697
|
||||
ipFamilies:
|
||||
- 斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ
|
||||
ipFamilyPolicy: 9ȫŚ
|
||||
loadBalancerIP: "27"
|
||||
loadBalancerSourceRanges:
|
||||
- "28"
|
||||
ports:
|
||||
- appProtocol: "20"
|
||||
name: "19"
|
||||
nodePort: -474380055
|
||||
port: 202283346
|
||||
protocol: '@Hr鯹)晿'
|
||||
targetPort: "21"
|
||||
publishNotReadyAddresses: true
|
||||
selector:
|
||||
"22": "23"
|
||||
sessionAffinity: 甞谐颋DžS
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 2072604405
|
||||
type: 鮽ort昍řČ扷5ƗǸƢ6/ʕVŚ(Ŀ
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2392-12-09T15:37:55Z"
|
||||
message: "36"
|
||||
observedGeneration: -2492120148461555858
|
||||
reason: "35"
|
||||
status: C
|
||||
type: "34"
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- hostname: "32"
|
||||
ip: "31"
|
||||
ports:
|
||||
- error: "33"
|
||||
port: -907310967
|
||||
protocol: 喂ƈ斎AO6
|
114
staging/src/k8s.io/api/testdata/v1.21.0/core.v1.Service.after_roundtrip.json
vendored
Normal file
114
staging/src/k8s.io/api/testdata/v1.21.0/core.v1.Service.after_roundtrip.json
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "2",
|
||||
"generateName": "3",
|
||||
"namespace": "4",
|
||||
"selfLink": "5",
|
||||
"uid": "7",
|
||||
"resourceVersion": "11042405498087606203",
|
||||
"generation": 8071137005907523419,
|
||||
"creationTimestamp": null,
|
||||
"deletionGracePeriodSeconds": -4955867275792137171,
|
||||
"labels": {
|
||||
"7": "8"
|
||||
},
|
||||
"annotations": {
|
||||
"9": "10"
|
||||
},
|
||||
"ownerReferences": [
|
||||
{
|
||||
"apiVersion": "11",
|
||||
"kind": "12",
|
||||
"name": "13",
|
||||
"uid": "Dz廔ȇ{sŊƏp",
|
||||
"controller": false,
|
||||
"blockOwnerDeletion": true
|
||||
}
|
||||
],
|
||||
"finalizers": [
|
||||
"14"
|
||||
],
|
||||
"clusterName": "15",
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "16",
|
||||
"operation": "鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć]",
|
||||
"apiVersion": "17",
|
||||
"fieldsType": "18"
|
||||
}
|
||||
]
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "19",
|
||||
"protocol": "@Hr鯹)晿",
|
||||
"appProtocol": "20",
|
||||
"port": 202283346,
|
||||
"targetPort": "21",
|
||||
"nodePort": -474380055
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"22": "23"
|
||||
},
|
||||
"clusterIP": "24",
|
||||
"clusterIPs": [
|
||||
"25"
|
||||
],
|
||||
"type": "鮽ort昍řČ扷5ƗǸƢ6/ʕVŚ(Ŀ",
|
||||
"externalIPs": [
|
||||
"26"
|
||||
],
|
||||
"sessionAffinity": "甞谐颋DžS",
|
||||
"loadBalancerIP": "27",
|
||||
"loadBalancerSourceRanges": [
|
||||
"28"
|
||||
],
|
||||
"externalName": "29",
|
||||
"externalTrafficPolicy": "ƏS$+½H牗洝尿",
|
||||
"healthCheckNodePort": -1965738697,
|
||||
"publishNotReadyAddresses": true,
|
||||
"sessionAffinityConfig": {
|
||||
"clientIP": {
|
||||
"timeoutSeconds": 2072604405
|
||||
}
|
||||
},
|
||||
"ipFamilies": [
|
||||
"斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ"
|
||||
],
|
||||
"ipFamilyPolicy": "9ȫŚ",
|
||||
"allocateLoadBalancerNodePorts": true,
|
||||
"loadBalancerClass": "31",
|
||||
"internalTrafficPolicy": ""
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {
|
||||
"ingress": [
|
||||
{
|
||||
"ip": "32",
|
||||
"hostname": "33",
|
||||
"ports": [
|
||||
{
|
||||
"port": 684408190,
|
||||
"protocol": "ƈ斎AO6ĴC浔Ű",
|
||||
"error": "34"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"type": "35",
|
||||
"status": "ž(-譵",
|
||||
"observedGeneration": -8651056334266075769,
|
||||
"lastTransitionTime": "2404-01-10T11:35:42Z",
|
||||
"reason": "36",
|
||||
"message": "37"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Binary file not shown.
80
staging/src/k8s.io/api/testdata/v1.21.0/core.v1.Service.after_roundtrip.yaml
vendored
Normal file
80
staging/src/k8s.io/api/testdata/v1.21.0/core.v1.Service.after_roundtrip.yaml
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
"9": "10"
|
||||
clusterName: "15"
|
||||
creationTimestamp: null
|
||||
deletionGracePeriodSeconds: -4955867275792137171
|
||||
finalizers:
|
||||
- "14"
|
||||
generateName: "3"
|
||||
generation: 8071137005907523419
|
||||
labels:
|
||||
"7": "8"
|
||||
managedFields:
|
||||
- apiVersion: "17"
|
||||
fieldsType: "18"
|
||||
manager: "16"
|
||||
operation: 鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć]
|
||||
name: "2"
|
||||
namespace: "4"
|
||||
ownerReferences:
|
||||
- apiVersion: "11"
|
||||
blockOwnerDeletion: true
|
||||
controller: false
|
||||
kind: "12"
|
||||
name: "13"
|
||||
uid: Dz廔ȇ{sŊƏp
|
||||
resourceVersion: "11042405498087606203"
|
||||
selfLink: "5"
|
||||
uid: "7"
|
||||
spec:
|
||||
allocateLoadBalancerNodePorts: true
|
||||
clusterIP: "24"
|
||||
clusterIPs:
|
||||
- "25"
|
||||
externalIPs:
|
||||
- "26"
|
||||
externalName: "29"
|
||||
externalTrafficPolicy: ƏS$+½H牗洝尿
|
||||
healthCheckNodePort: -1965738697
|
||||
internalTrafficPolicy: ""
|
||||
ipFamilies:
|
||||
- 斬³;Ơ歿:狞夌碕ʂɭîcP$Iņɖ
|
||||
ipFamilyPolicy: 9ȫŚ
|
||||
loadBalancerClass: "31"
|
||||
loadBalancerIP: "27"
|
||||
loadBalancerSourceRanges:
|
||||
- "28"
|
||||
ports:
|
||||
- appProtocol: "20"
|
||||
name: "19"
|
||||
nodePort: -474380055
|
||||
port: 202283346
|
||||
protocol: '@Hr鯹)晿'
|
||||
targetPort: "21"
|
||||
publishNotReadyAddresses: true
|
||||
selector:
|
||||
"22": "23"
|
||||
sessionAffinity: 甞谐颋DžS
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 2072604405
|
||||
type: 鮽ort昍řČ扷5ƗǸƢ6/ʕVŚ(Ŀ
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2404-01-10T11:35:42Z"
|
||||
message: "37"
|
||||
observedGeneration: -8651056334266075769
|
||||
reason: "36"
|
||||
status: ž(-譵
|
||||
type: "35"
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- hostname: "33"
|
||||
ip: "32"
|
||||
ports:
|
||||
- error: "34"
|
||||
port: 684408190
|
||||
protocol: ƈ斎AO6ĴC浔Ű
|
@ -39,7 +39,6 @@ type ServiceSpecApplyConfiguration struct {
|
||||
HealthCheckNodePort *int32 `json:"healthCheckNodePort,omitempty"`
|
||||
PublishNotReadyAddresses *bool `json:"publishNotReadyAddresses,omitempty"`
|
||||
SessionAffinityConfig *SessionAffinityConfigApplyConfiguration `json:"sessionAffinityConfig,omitempty"`
|
||||
TopologyKeys []string `json:"topologyKeys,omitempty"`
|
||||
IPFamilies []corev1.IPFamily `json:"ipFamilies,omitempty"`
|
||||
IPFamilyPolicy *corev1.IPFamilyPolicyType `json:"ipFamilyPolicy,omitempty"`
|
||||
AllocateLoadBalancerNodePorts *bool `json:"allocateLoadBalancerNodePorts,omitempty"`
|
||||
@ -182,16 +181,6 @@ func (b *ServiceSpecApplyConfiguration) WithSessionAffinityConfig(value *Session
|
||||
return b
|
||||
}
|
||||
|
||||
// WithTopologyKeys adds the given value to the TopologyKeys field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the TopologyKeys field.
|
||||
func (b *ServiceSpecApplyConfiguration) WithTopologyKeys(values ...string) *ServiceSpecApplyConfiguration {
|
||||
for i := range values {
|
||||
b.TopologyKeys = append(b.TopologyKeys, values[i])
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// WithIPFamilies adds the given value to the IPFamilies field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the IPFamilies field.
|
||||
|
@ -6235,12 +6235,6 @@ var schemaYAML = typed.YAMLObject(`types:
|
||||
- name: sessionAffinityConfig
|
||||
type:
|
||||
namedType: io.k8s.api.core.v1.SessionAffinityConfig
|
||||
- name: topologyKeys
|
||||
type:
|
||||
list:
|
||||
elementType:
|
||||
scalar: string
|
||||
elementRelationship: atomic
|
||||
- name: type
|
||||
type:
|
||||
scalar: string
|
||||
|
Loading…
Reference in New Issue
Block a user