mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Splitting IP address type into IPv4 and IPv6 for EndpointSlices
This commit is contained in:
parent
bcb171b375
commit
0fa9981e01
5
api/openapi-spec/swagger.json
generated
5
api/openapi-spec/swagger.json
generated
@ -12025,7 +12025,7 @@
|
||||
"description": "Endpoint represents a single logical \"backend\" implementing a service.",
|
||||
"properties": {
|
||||
"addresses": {
|
||||
"description": "addresses of this endpoint. The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. This allows for cases like dual-stack networking where both IPv4 and IPv6 addresses would be included with the IP addressType. Consumers (e.g. kube-proxy) must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100.",
|
||||
"description": "addresses of this endpoint. The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. Consumers must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -12094,7 +12094,7 @@
|
||||
"description": "EndpointSlice represents a subset of the endpoints that implement a service. For a given service there may be multiple EndpointSlice objects, selected by labels, which must be joined to produce the full set of endpoints.",
|
||||
"properties": {
|
||||
"addressType": {
|
||||
"description": "addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. The following address types are currently supported: * IP: Represents an IP Address. This can include both IPv4 and IPv6\n addresses.\n* FQDN: Represents a Fully Qualified Domain Name. Default is IP",
|
||||
"description": "addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name.",
|
||||
"type": "string"
|
||||
},
|
||||
"apiVersion": {
|
||||
@ -12127,6 +12127,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"addressType",
|
||||
"endpoints"
|
||||
],
|
||||
"type": "object",
|
||||
|
@ -30,11 +30,8 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
func(obj *discovery.EndpointSlice, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj) // fuzz self without calling this function again
|
||||
|
||||
// match defaults
|
||||
if obj.AddressType == nil {
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
obj.AddressType = &ipAddressType
|
||||
}
|
||||
addressTypes := []discovery.AddressType{discovery.AddressTypeIPv4, discovery.AddressTypeIPv6, discovery.AddressTypeFQDN}
|
||||
obj.AddressType = addressTypes[c.Rand.Intn(len(addressTypes))]
|
||||
|
||||
for i, endpointPort := range obj.Ports {
|
||||
if endpointPort.Name == nil {
|
||||
|
@ -32,13 +32,13 @@ type EndpointSlice struct {
|
||||
// +optional
|
||||
metav1.ObjectMeta
|
||||
// addressType specifies the type of address carried by this EndpointSlice.
|
||||
// All addresses in this slice must be the same type. The following address
|
||||
// types are currently supported:
|
||||
// * IP: Represents an IP Address. This can include both IPv4 and IPv6
|
||||
// addresses.
|
||||
// All addresses in this slice must be the same type. This field is
|
||||
// immutable after creation. The following address types are currently
|
||||
// supported:
|
||||
// * IPv4: Represents an IPv4 Address.
|
||||
// * IPv6: Represents an IPv6 Address.
|
||||
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||
// +optional
|
||||
AddressType *AddressType
|
||||
AddressType AddressType
|
||||
// endpoints is a list of unique endpoints in this slice. Each slice may
|
||||
// include a maximum of 1000 endpoints.
|
||||
// +listType=atomic
|
||||
@ -57,22 +57,27 @@ type EndpointSlice struct {
|
||||
type AddressType string
|
||||
|
||||
const (
|
||||
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||
// addresses.
|
||||
// AddressTypeIP represents an IP Address.
|
||||
// This address type has been deprecated and has been replaced by the IPv4
|
||||
// and IPv6 adddress types. New resources with this address type will be
|
||||
// considered invalid. This will be fully removed in 1.18.
|
||||
// +deprecated
|
||||
AddressTypeIP = AddressType("IP")
|
||||
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||
// AddressTypeIPv4 represents an IPv4 Address.
|
||||
AddressTypeIPv4 = AddressType(api.IPv4Protocol)
|
||||
// AddressTypeIPv6 represents an IPv6 Address.
|
||||
AddressTypeIPv6 = AddressType(api.IPv6Protocol)
|
||||
// AddressTypeFQDN represents a FQDN.
|
||||
AddressTypeFQDN = AddressType("FQDN")
|
||||
)
|
||||
|
||||
// Endpoint represents a single logical "backend" implementing a service.
|
||||
type Endpoint struct {
|
||||
// addresses of this endpoint. The contents of this field are interpreted
|
||||
// according to the corresponding EndpointSlice addressType field. This
|
||||
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||
// kube-proxy) must handle different types of addresses in the context of
|
||||
// their own capabilities. This must contain at least one address but no
|
||||
// more than 100.
|
||||
// according to the corresponding EndpointSlice addressType field. Consumers
|
||||
// must handle different types of addresses in the context of their own
|
||||
// capabilities. This must contain at least one address but no more than
|
||||
// 100.
|
||||
// +listType=set
|
||||
Addresses []string
|
||||
// conditions contains information about the current status of the endpoint.
|
||||
|
@ -23,21 +23,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
defaultAddressType = discoveryv1alpha1.AddressTypeIP
|
||||
defaultPortName = ""
|
||||
defaultProtocol = v1.ProtocolTCP
|
||||
defaultPortName = ""
|
||||
defaultProtocol = v1.ProtocolTCP
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
return RegisterDefaults(scheme)
|
||||
}
|
||||
|
||||
func SetDefaults_EndpointSlice(obj *discoveryv1alpha1.EndpointSlice) {
|
||||
if obj.AddressType == nil {
|
||||
obj.AddressType = &defaultAddressType
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_EndpointPort(obj *discoveryv1alpha1.EndpointPort) {
|
||||
if obj.Name == nil {
|
||||
obj.Name = &defaultPortName
|
||||
|
@ -33,8 +33,6 @@ func TestSetDefaultEndpointPort(t *testing.T) {
|
||||
fooStr := "foo"
|
||||
protoTCP := v1.ProtocolTCP
|
||||
protoUDP := v1.ProtocolUDP
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
otherAddressType := discovery.AddressType("other")
|
||||
|
||||
tests := map[string]struct {
|
||||
original *discovery.EndpointSlice
|
||||
@ -45,7 +43,6 @@ func TestSetDefaultEndpointPort(t *testing.T) {
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
}}},
|
||||
expected: &discovery.EndpointSlice{
|
||||
AddressType: &ipAddressType,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: &emptyStr,
|
||||
Protocol: &protoTCP,
|
||||
@ -55,14 +52,12 @@ func TestSetDefaultEndpointPort(t *testing.T) {
|
||||
},
|
||||
"should not overwrite values with defaults when set": {
|
||||
original: &discovery.EndpointSlice{
|
||||
AddressType: &otherAddressType,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: &fooStr,
|
||||
Protocol: &protoUDP,
|
||||
}},
|
||||
},
|
||||
expected: &discovery.EndpointSlice{
|
||||
AddressType: &otherAddressType,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: &fooStr,
|
||||
Protocol: &protoUDP,
|
||||
|
@ -171,7 +171,7 @@ func Convert_discovery_EndpointPort_To_v1alpha1_EndpointPort(in *discovery.Endpo
|
||||
|
||||
func autoConvert_v1alpha1_EndpointSlice_To_discovery_EndpointSlice(in *v1alpha1.EndpointSlice, out *discovery.EndpointSlice, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.AddressType = (*discovery.AddressType)(unsafe.Pointer(in.AddressType))
|
||||
out.AddressType = discovery.AddressType(in.AddressType)
|
||||
out.Endpoints = *(*[]discovery.Endpoint)(unsafe.Pointer(&in.Endpoints))
|
||||
out.Ports = *(*[]discovery.EndpointPort)(unsafe.Pointer(&in.Ports))
|
||||
return nil
|
||||
@ -184,7 +184,7 @@ func Convert_v1alpha1_EndpointSlice_To_discovery_EndpointSlice(in *v1alpha1.Endp
|
||||
|
||||
func autoConvert_discovery_EndpointSlice_To_v1alpha1_EndpointSlice(in *discovery.EndpointSlice, out *v1alpha1.EndpointSlice, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.AddressType = (*v1alpha1.AddressType)(unsafe.Pointer(in.AddressType))
|
||||
out.AddressType = v1alpha1.AddressType(in.AddressType)
|
||||
out.Endpoints = *(*[]v1alpha1.Endpoint)(unsafe.Pointer(&in.Endpoints))
|
||||
out.Ports = *(*[]v1alpha1.EndpointPort)(unsafe.Pointer(&in.Ports))
|
||||
return nil
|
||||
|
@ -35,7 +35,6 @@ func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
}
|
||||
|
||||
func SetObjectDefaults_EndpointSlice(in *v1alpha1.EndpointSlice) {
|
||||
SetDefaults_EndpointSlice(in)
|
||||
for i := range in.Ports {
|
||||
a := &in.Ports[i]
|
||||
SetDefaults_EndpointPort(a)
|
||||
|
@ -28,12 +28,23 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
supportedAddressTypes = sets.NewString(string(discovery.AddressTypeIP), string(discovery.AddressTypeFQDN))
|
||||
supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP), string(api.ProtocolSCTP))
|
||||
maxTopologyLabels = 16
|
||||
maxAddresses = 100
|
||||
maxPorts = 100
|
||||
maxEndpoints = 1000
|
||||
supportedAddressTypes = sets.NewString(
|
||||
string(discovery.AddressTypeIPv4),
|
||||
string(discovery.AddressTypeIPv6),
|
||||
string(discovery.AddressTypeFQDN),
|
||||
)
|
||||
deprecatedAddressTypes = sets.NewString(
|
||||
string(discovery.AddressTypeIP),
|
||||
)
|
||||
supportedPortProtocols = sets.NewString(
|
||||
string(api.ProtocolTCP),
|
||||
string(api.ProtocolUDP),
|
||||
string(api.ProtocolSCTP),
|
||||
)
|
||||
maxTopologyLabels = 16
|
||||
maxAddresses = 100
|
||||
maxPorts = 100
|
||||
maxEndpoints = 1000
|
||||
)
|
||||
|
||||
// ValidateEndpointSliceName can be used to check whether the given endpoint
|
||||
@ -42,33 +53,24 @@ var (
|
||||
var ValidateEndpointSliceName = apimachineryvalidation.NameIsDNSSubdomain
|
||||
|
||||
// ValidateEndpointSlice validates an EndpointSlice.
|
||||
func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) field.ErrorList {
|
||||
func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice, validAddressTypes sets.String) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMeta(&endpointSlice.ObjectMeta, true, ValidateEndpointSliceName, field.NewPath("metadata"))
|
||||
|
||||
// AddressType should have had a default value set at this point, this is
|
||||
// just a safety check if for some reason that changes or doesn't work.
|
||||
addrType := discovery.AddressType("")
|
||||
if endpointSlice.AddressType == nil {
|
||||
allErrs = append(allErrs, field.Required(field.NewPath("addressType"), ""))
|
||||
} else {
|
||||
addrType = *endpointSlice.AddressType
|
||||
}
|
||||
|
||||
if !supportedAddressTypes.Has(string(addrType)) {
|
||||
allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), addrType, supportedAddressTypes.List()))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateEndpoints(endpointSlice.Endpoints, addrType, field.NewPath("endpoints"))...)
|
||||
allErrs = append(allErrs, validateAddressType(endpointSlice.AddressType, validAddressTypes)...)
|
||||
allErrs = append(allErrs, validateEndpoints(endpointSlice.Endpoints, endpointSlice.AddressType, field.NewPath("endpoints"))...)
|
||||
allErrs = append(allErrs, validatePorts(endpointSlice.Ports, field.NewPath("ports"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateEndpointSliceCreate validates an EndpointSlice when it is created.
|
||||
func ValidateEndpointSliceCreate(endpointSlice *discovery.EndpointSlice) field.ErrorList {
|
||||
return ValidateEndpointSlice(endpointSlice, supportedAddressTypes)
|
||||
}
|
||||
|
||||
// ValidateEndpointSliceUpdate validates an EndpointSlice when it is updated.
|
||||
func ValidateEndpointSliceUpdate(newEndpointSlice, oldEndpointSlice *discovery.EndpointSlice) field.ErrorList {
|
||||
allErrs := ValidateEndpointSlice(newEndpointSlice)
|
||||
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(*newEndpointSlice.AddressType, *oldEndpointSlice.AddressType, field.NewPath("addressType"))...)
|
||||
allErrs := ValidateEndpointSlice(newEndpointSlice, supportedAddressTypes.Union(deprecatedAddressTypes))
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(newEndpointSlice.AddressType, oldEndpointSlice.AddressType, field.NewPath("addressType"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
@ -92,11 +94,17 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres
|
||||
}
|
||||
|
||||
for i, address := range endpoint.Addresses {
|
||||
// This validates known address types, unknown types fall through
|
||||
// and do not get validated.
|
||||
switch addrType {
|
||||
case discovery.AddressTypeIP:
|
||||
for _, msg := range validation.IsValidIP(address) {
|
||||
allErrs = append(allErrs, field.Invalid(addressPath.Index(i), address, msg))
|
||||
}
|
||||
case discovery.AddressTypeIPv4:
|
||||
allErrs = append(allErrs, validation.IsValidIPv4Address(addressPath.Index(i), address)...)
|
||||
case discovery.AddressTypeIPv6:
|
||||
allErrs = append(allErrs, validation.IsValidIPv6Address(addressPath.Index(i), address)...)
|
||||
case discovery.AddressTypeFQDN:
|
||||
allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
|
||||
}
|
||||
@ -153,3 +161,15 @@ func validatePorts(endpointPorts []discovery.EndpointPort, fldPath *field.Path)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateAddressType(addressType discovery.AddressType, validAddressTypes sets.String) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if addressType == "" {
|
||||
allErrs = append(allErrs, field.Required(field.NewPath("addressType"), ""))
|
||||
} else if !validAddressTypes.Has(string(addressType)) {
|
||||
allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), addressType, validAddressTypes.List()))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -56,7 +56,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeFQDN),
|
||||
AddressType: discovery.AddressTypeFQDN,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -71,7 +71,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("tcp"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -92,7 +92,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("one"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -120,7 +120,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr(""),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -137,7 +137,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr(strings.Repeat("a", 63)),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -151,7 +151,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{},
|
||||
Endpoints: []discovery.Endpoint{},
|
||||
},
|
||||
@ -160,7 +160,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: generatePorts(1),
|
||||
Endpoints: generateEndpoints(maxEndpoints),
|
||||
},
|
||||
@ -169,7 +169,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: generatePorts(maxPorts),
|
||||
},
|
||||
},
|
||||
@ -177,7 +177,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -191,7 +191,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -208,7 +208,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr(""),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -223,7 +223,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("aCapital"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -235,7 +235,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("almost_valid"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -247,7 +247,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr(strings.Repeat("a", 64)),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -259,7 +259,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.Protocol("foo")),
|
||||
@ -270,7 +270,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: generatePorts(maxPorts + 1),
|
||||
},
|
||||
},
|
||||
@ -278,7 +278,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: generatePorts(1),
|
||||
Endpoints: generateEndpoints(maxEndpoints + 1),
|
||||
},
|
||||
@ -287,7 +287,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -301,7 +301,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -311,25 +311,11 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-address-type": {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressType("other")),
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateIPAddresses(1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-topology-key": {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -344,7 +330,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -359,7 +345,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -377,7 +363,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Name: "*&^",
|
||||
Namespace: "foo",
|
||||
},
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -392,7 +378,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -403,11 +389,41 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-ipv4": {
|
||||
expectedErrors: 2,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: []string{"123.456.789.012", "2001:4860:4860::8888"},
|
||||
Hostname: utilpointer.StringPtr("valid-123"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-ipv6": {
|
||||
expectedErrors: 2,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIPv6,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: []string{"123.456.789.012", "2001:4860:4860:defg"},
|
||||
Hostname: utilpointer.StringPtr("valid-123"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-fqdns": {
|
||||
expectedErrors: 4,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeFQDN),
|
||||
AddressType: discovery.AddressTypeFQDN,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -422,7 +438,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
@ -436,15 +452,80 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
},
|
||||
"empty-everything": {
|
||||
expectedErrors: 3,
|
||||
endpointSlice: &discovery.EndpointSlice{},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
errs := ValidateEndpointSlice(testCase.endpointSlice, supportedAddressTypes.Union(deprecatedAddressTypes))
|
||||
if len(errs) != testCase.expectedErrors {
|
||||
t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEndpointSliceCreate(t *testing.T) {
|
||||
standardMeta := metav1.ObjectMeta{
|
||||
Name: "hello",
|
||||
Namespace: "world",
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
expectedErrors int
|
||||
endpointSlice *discovery.EndpointSlice
|
||||
}{
|
||||
"good-slice": {
|
||||
expectedErrors: 0,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
AddressType: addressTypePtr(""),
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateIPAddresses(1),
|
||||
Hostname: utilpointer.StringPtr("valid-123"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
||||
// expected failures
|
||||
"deprecated-address-type": {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateIPAddresses(1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
"bad-address-type": {
|
||||
expectedErrors: 1,
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressType("other"),
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateIPAddresses(1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
errs := ValidateEndpointSlice(testCase.endpointSlice)
|
||||
errs := ValidateEndpointSliceCreate(testCase.endpointSlice)
|
||||
if len(errs) != testCase.expectedErrors {
|
||||
t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs)
|
||||
}
|
||||
@ -463,29 +544,40 @@ func TestValidateEndpointSliceUpdate(t *testing.T) {
|
||||
"valid and identical slices": {
|
||||
newEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv6,
|
||||
},
|
||||
oldEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIPv6,
|
||||
},
|
||||
expectedErrors: 0,
|
||||
},
|
||||
"deprecated address type": {
|
||||
expectedErrors: 0,
|
||||
newEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
},
|
||||
oldEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
},
|
||||
},
|
||||
"valid and identical slices with different address types": {
|
||||
newEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
},
|
||||
oldEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressType("other")),
|
||||
AddressType: discovery.AddressType("other"),
|
||||
},
|
||||
expectedErrors: 1,
|
||||
},
|
||||
"invalid slices with valid address types": {
|
||||
newEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr(""),
|
||||
Protocol: protocolPtr(api.Protocol("invalid")),
|
||||
@ -493,7 +585,7 @@ func TestValidateEndpointSliceUpdate(t *testing.T) {
|
||||
},
|
||||
oldEndpointSlice: &discovery.EndpointSlice{
|
||||
ObjectMeta: standardMeta,
|
||||
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||
AddressType: discovery.AddressTypeIP,
|
||||
},
|
||||
expectedErrors: 1,
|
||||
},
|
||||
@ -515,10 +607,6 @@ func protocolPtr(protocol api.Protocol) *api.Protocol {
|
||||
return &protocol
|
||||
}
|
||||
|
||||
func addressTypePtr(addressType discovery.AddressType) *discovery.AddressType {
|
||||
return &addressType
|
||||
}
|
||||
|
||||
func generatePorts(n int) []discovery.EndpointPort {
|
||||
ports := []discovery.EndpointPort{}
|
||||
for i := 0; i < n; i++ {
|
||||
|
5
pkg/apis/discovery/zz_generated.deepcopy.go
generated
5
pkg/apis/discovery/zz_generated.deepcopy.go
generated
@ -126,11 +126,6 @@ func (in *EndpointSlice) DeepCopyInto(out *EndpointSlice) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.AddressType != nil {
|
||||
in, out := &in.AddressType, &out.AddressType
|
||||
*out = new(AddressType)
|
||||
**out = **in
|
||||
}
|
||||
if in.Endpoints != nil {
|
||||
in, out := &in.Endpoints, &out.Endpoints
|
||||
*out = make([]Endpoint, len(*in))
|
||||
|
@ -41,6 +41,7 @@ go_library(
|
||||
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/metrics/prometheus/ratelimiter:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/utils/net:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -198,6 +198,7 @@ func TestSyncServiceEndpointSliceLabelSelection(t *testing.T) {
|
||||
discovery.LabelManagedBy: controllerName,
|
||||
},
|
||||
},
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
}, {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "matching-2",
|
||||
@ -207,6 +208,7 @@ func TestSyncServiceEndpointSliceLabelSelection(t *testing.T) {
|
||||
discovery.LabelManagedBy: controllerName,
|
||||
},
|
||||
},
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
}, {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "partially-matching-1",
|
||||
@ -215,6 +217,7 @@ func TestSyncServiceEndpointSliceLabelSelection(t *testing.T) {
|
||||
discovery.LabelServiceName: serviceName,
|
||||
},
|
||||
},
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
}, {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "not-matching-1",
|
||||
@ -224,6 +227,7 @@ func TestSyncServiceEndpointSliceLabelSelection(t *testing.T) {
|
||||
discovery.LabelManagedBy: controllerName,
|
||||
},
|
||||
},
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
}, {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "not-matching-2",
|
||||
@ -233,6 +237,7 @@ func TestSyncServiceEndpointSliceLabelSelection(t *testing.T) {
|
||||
discovery.LabelManagedBy: "something-else",
|
||||
},
|
||||
},
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
}}
|
||||
|
||||
// need to add them to both store and fake clientset
|
||||
@ -272,16 +277,13 @@ func TestSyncServiceFull(t *testing.T) {
|
||||
client, esController := newController([]string{"node-1"})
|
||||
namespace := metav1.NamespaceDefault
|
||||
serviceName := "all-the-protocols"
|
||||
ipv6Family := v1.IPv6Protocol
|
||||
|
||||
// pod 1 only uses PodIP status attr
|
||||
pod1 := newPod(1, namespace, true, 0)
|
||||
pod1.Status.PodIP = "1.2.3.4"
|
||||
pod1.Status.PodIPs = []v1.PodIP{}
|
||||
pod1.Status.PodIPs = []v1.PodIP{{IP: "1.2.3.4"}}
|
||||
esController.podStore.Add(pod1)
|
||||
|
||||
// pod 2 only uses PodIPs status attr
|
||||
pod2 := newPod(2, namespace, true, 0)
|
||||
pod2.Status.PodIP = ""
|
||||
pod2.Status.PodIPs = []v1.PodIP{{IP: "1.2.3.5"}, {IP: "1234::5678:0000:0000:9abc:def0"}}
|
||||
esController.podStore.Add(pod2)
|
||||
|
||||
@ -300,6 +302,7 @@ func TestSyncServiceFull(t *testing.T) {
|
||||
{Name: "sctp-example", TargetPort: intstr.FromInt(3456), Protocol: v1.ProtocolSCTP},
|
||||
},
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
IPFamily: &ipv6Family,
|
||||
},
|
||||
}
|
||||
esController.serviceStore.Add(service)
|
||||
@ -318,7 +321,7 @@ func TestSyncServiceFull(t *testing.T) {
|
||||
|
||||
// ensure all attributes of endpoint slice match expected state
|
||||
slice := sliceList.Items[0]
|
||||
assert.Len(t, slice.Endpoints, 2, "Expected 2 endpoints in first slice")
|
||||
assert.Len(t, slice.Endpoints, 1, "Expected 1 endpoints in first slice")
|
||||
assert.Equal(t, slice.Annotations["endpoints.kubernetes.io/last-change-trigger-time"], serviceCreateTime.Format(time.RFC3339Nano))
|
||||
assert.ElementsMatch(t, []discovery.EndpointPort{{
|
||||
Name: strPtr("tcp-example"),
|
||||
@ -336,12 +339,7 @@ func TestSyncServiceFull(t *testing.T) {
|
||||
|
||||
assert.ElementsMatch(t, []discovery.Endpoint{{
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Addresses: []string{"1.2.3.4"},
|
||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: namespace, Name: pod1.Name},
|
||||
Topology: map[string]string{"kubernetes.io/hostname": "node-1"},
|
||||
}, {
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Addresses: []string{"1.2.3.5", "1234::5678:0000:0000:9abc:def0"},
|
||||
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: namespace, Name: pod2.Name},
|
||||
Topology: map[string]string{"kubernetes.io/hostname": "node-1"},
|
||||
}}, slice.Endpoints)
|
||||
|
@ -47,7 +47,7 @@ type reconciler struct {
|
||||
// that logic in reconciler
|
||||
type endpointMeta struct {
|
||||
Ports []discovery.EndpointPort `json:"ports" protobuf:"bytes,2,rep,name=ports"`
|
||||
AddressType *discovery.AddressType `json:"addressType" protobuf:"bytes,3,rep,name=addressType"`
|
||||
AddressType discovery.AddressType `json:"addressType" protobuf:"bytes,3,rep,name=addressType"`
|
||||
}
|
||||
|
||||
// reconcile takes a set of pods currently matching a service selector and
|
||||
@ -55,13 +55,26 @@ type endpointMeta struct {
|
||||
// slices for the given service. It creates, updates, or deletes endpoint slices
|
||||
// to ensure the desired set of pods are represented by endpoint slices.
|
||||
func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, existingSlices []*discovery.EndpointSlice, triggerTime time.Time) error {
|
||||
addressType := discovery.AddressTypeIPv4
|
||||
if service.Spec.IPFamily != nil && *service.Spec.IPFamily == corev1.IPv6Protocol {
|
||||
addressType = discovery.AddressTypeIPv6
|
||||
}
|
||||
|
||||
slicesToCreate := []*discovery.EndpointSlice{}
|
||||
slicesToUpdate := []*discovery.EndpointSlice{}
|
||||
slicesToDelete := []*discovery.EndpointSlice{}
|
||||
|
||||
// Build data structures for existing state.
|
||||
existingSlicesByPortMap := map[endpointutil.PortMapKey][]*discovery.EndpointSlice{}
|
||||
numExistingEndpoints := 0
|
||||
for _, existingSlice := range existingSlices {
|
||||
epHash := endpointutil.NewPortMapKey(existingSlice.Ports)
|
||||
existingSlicesByPortMap[epHash] = append(existingSlicesByPortMap[epHash], existingSlice)
|
||||
numExistingEndpoints += len(existingSlice.Endpoints)
|
||||
if existingSlice.AddressType == addressType {
|
||||
epHash := endpointutil.NewPortMapKey(existingSlice.Ports)
|
||||
existingSlicesByPortMap[epHash] = append(existingSlicesByPortMap[epHash], existingSlice)
|
||||
numExistingEndpoints += len(existingSlice.Endpoints)
|
||||
} else {
|
||||
slicesToDelete = append(slicesToDelete, existingSlice)
|
||||
}
|
||||
}
|
||||
|
||||
// Build data structures for desired state.
|
||||
@ -78,10 +91,8 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
}
|
||||
|
||||
if _, ok := desiredMetaByPortMap[epHash]; !ok {
|
||||
// TODO: Support multiple backend types
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
desiredMetaByPortMap[epHash] = &endpointMeta{
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: addressType,
|
||||
Ports: endpointPorts,
|
||||
}
|
||||
}
|
||||
@ -90,16 +101,14 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint := podToEndpoint(pod, node, service)
|
||||
desiredEndpointsByPortMap[epHash].Insert(&endpoint)
|
||||
numDesiredEndpoints++
|
||||
if len(endpoint.Addresses) > 0 {
|
||||
desiredEndpointsByPortMap[epHash].Insert(&endpoint)
|
||||
numDesiredEndpoints++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slicesToCreate := []*discovery.EndpointSlice{}
|
||||
slicesToUpdate := []*discovery.EndpointSlice{}
|
||||
sliceNamesToDelete := sets.String{}
|
||||
spMetrics := metrics.NewServicePortCache()
|
||||
totalAdded := 0
|
||||
totalRemoved := 0
|
||||
@ -107,7 +116,7 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
// Determine changes necessary for each group of slices by port map.
|
||||
for portMap, desiredEndpoints := range desiredEndpointsByPortMap {
|
||||
numEndpoints := len(desiredEndpoints)
|
||||
pmSlicesToCreate, pmSlicesToUpdate, pmSliceNamesToDelete, added, removed := r.reconcileByPortMapping(
|
||||
pmSlicesToCreate, pmSlicesToUpdate, pmSlicesToDelete, added, removed := r.reconcileByPortMapping(
|
||||
service, existingSlicesByPortMap[portMap], desiredEndpoints, desiredMetaByPortMap[portMap])
|
||||
|
||||
totalAdded += added
|
||||
@ -115,7 +124,7 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
|
||||
spMetrics.Set(portMap, metrics.EfficiencyInfo{
|
||||
Endpoints: numEndpoints,
|
||||
Slices: len(existingSlicesByPortMap[portMap]) + len(pmSlicesToCreate) - len(pmSliceNamesToDelete),
|
||||
Slices: len(existingSlicesByPortMap[portMap]) + len(pmSlicesToCreate) - len(pmSlicesToDelete),
|
||||
})
|
||||
|
||||
if len(pmSlicesToCreate) > 0 {
|
||||
@ -124,8 +133,8 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
if len(pmSlicesToUpdate) > 0 {
|
||||
slicesToUpdate = append(slicesToUpdate, pmSlicesToUpdate...)
|
||||
}
|
||||
if pmSliceNamesToDelete.Len() > 0 {
|
||||
sliceNamesToDelete = sliceNamesToDelete.Union(pmSliceNamesToDelete)
|
||||
if len(pmSlicesToDelete) > 0 {
|
||||
slicesToDelete = append(slicesToDelete, pmSlicesToDelete...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,14 +143,14 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
for portMap, existingSlices := range existingSlicesByPortMap {
|
||||
if _, ok := desiredEndpointsByPortMap[portMap]; !ok {
|
||||
for _, existingSlice := range existingSlices {
|
||||
sliceNamesToDelete.Insert(existingSlice.Name)
|
||||
slicesToDelete = append(slicesToDelete, existingSlice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When no endpoint slices would usually exist, we need to add a placeholder.
|
||||
if len(existingSlices) == sliceNamesToDelete.Len() && len(slicesToCreate) < 1 {
|
||||
placeholderSlice := newEndpointSlice(service, &endpointMeta{Ports: []discovery.EndpointPort{}})
|
||||
if len(existingSlices) == len(slicesToDelete) && len(slicesToCreate) < 1 {
|
||||
placeholderSlice := newEndpointSlice(service, &endpointMeta{Ports: []discovery.EndpointPort{}, AddressType: addressType})
|
||||
slicesToCreate = append(slicesToCreate, placeholderSlice)
|
||||
spMetrics.Set(endpointutil.NewPortMapKey(placeholderSlice.Ports), metrics.EfficiencyInfo{
|
||||
Endpoints: 0,
|
||||
@ -155,27 +164,41 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
|
||||
serviceNN := types.NamespacedName{Name: service.Name, Namespace: service.Namespace}
|
||||
r.metricsCache.UpdateServicePortCache(serviceNN, spMetrics)
|
||||
|
||||
return r.finalize(service, slicesToCreate, slicesToUpdate, sliceNamesToDelete, triggerTime)
|
||||
return r.finalize(service, slicesToCreate, slicesToUpdate, slicesToDelete, triggerTime)
|
||||
}
|
||||
|
||||
// finalize creates, updates, and deletes slices as specified
|
||||
func (r *reconciler) finalize(
|
||||
service *corev1.Service,
|
||||
slicesToCreate,
|
||||
slicesToUpdate []*discovery.EndpointSlice,
|
||||
sliceNamesToDelete sets.String,
|
||||
slicesToUpdate,
|
||||
slicesToDelete []*discovery.EndpointSlice,
|
||||
triggerTime time.Time,
|
||||
) error {
|
||||
errs := []error{}
|
||||
|
||||
// If there are slices to create and delete, change the creates to updates
|
||||
// of the slices that would otherwise be deleted.
|
||||
for len(slicesToCreate) > 0 && sliceNamesToDelete.Len() > 0 {
|
||||
sliceName, _ := sliceNamesToDelete.PopAny()
|
||||
for i := 0; i < len(slicesToDelete); {
|
||||
if len(slicesToCreate) == 0 {
|
||||
break
|
||||
}
|
||||
sliceToDelete := slicesToDelete[i]
|
||||
slice := slicesToCreate[len(slicesToCreate)-1]
|
||||
slicesToCreate = slicesToCreate[:len(slicesToCreate)-1]
|
||||
slice.Name = sliceName
|
||||
slicesToUpdate = append(slicesToUpdate, slice)
|
||||
// Only update EndpointSlices that have the same AddressType as this
|
||||
// field is considered immutable. Since Services also consider IPFamily
|
||||
// immutable, the only case where this should matter will be the
|
||||
// migration from IP to IPv4 and IPv6 AddressTypes, where there's a
|
||||
// chance EndpointSlices with an IP AddressType would otherwise be
|
||||
// updated to IPv4 or IPv6 without this check.
|
||||
if sliceToDelete.AddressType == slice.AddressType {
|
||||
slice.Name = sliceToDelete.Name
|
||||
slicesToCreate = slicesToCreate[:len(slicesToCreate)-1]
|
||||
slicesToUpdate = append(slicesToUpdate, slice)
|
||||
slicesToDelete = append(slicesToDelete[:i], slicesToDelete[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
for _, endpointSlice := range slicesToCreate {
|
||||
@ -202,11 +225,10 @@ func (r *reconciler) finalize(
|
||||
}
|
||||
}
|
||||
|
||||
for sliceNamesToDelete.Len() > 0 {
|
||||
sliceName, _ := sliceNamesToDelete.PopAny()
|
||||
err := r.client.DiscoveryV1alpha1().EndpointSlices(service.Namespace).Delete(sliceName, &metav1.DeleteOptions{})
|
||||
for _, endpointSlice := range slicesToDelete {
|
||||
err := r.client.DiscoveryV1alpha1().EndpointSlices(service.Namespace).Delete(endpointSlice.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Error deleting %s EndpointSlice for Service %s/%s: %v", sliceName, service.Namespace, service.Name, err))
|
||||
errs = append(errs, fmt.Errorf("Error deleting %s EndpointSlice for Service %s/%s: %v", endpointSlice.Name, service.Namespace, service.Name, err))
|
||||
} else {
|
||||
metrics.EndpointSliceChanges.WithLabelValues("delete").Inc()
|
||||
}
|
||||
@ -229,7 +251,7 @@ func (r *reconciler) reconcileByPortMapping(
|
||||
existingSlices []*discovery.EndpointSlice,
|
||||
desiredSet endpointSet,
|
||||
endpointMeta *endpointMeta,
|
||||
) ([]*discovery.EndpointSlice, []*discovery.EndpointSlice, sets.String, int, int) {
|
||||
) ([]*discovery.EndpointSlice, []*discovery.EndpointSlice, []*discovery.EndpointSlice, int, int) {
|
||||
slicesByName := map[string]*discovery.EndpointSlice{}
|
||||
sliceNamesUnchanged := sets.String{}
|
||||
sliceNamesToUpdate := sets.String{}
|
||||
@ -345,7 +367,13 @@ func (r *reconciler) reconcileByPortMapping(
|
||||
slicesToUpdate = append(slicesToUpdate, slicesByName[sliceName])
|
||||
}
|
||||
|
||||
return slicesToCreate, slicesToUpdate, sliceNamesToDelete, numAdded, numRemoved
|
||||
// Build slicesToDelete from slice names.
|
||||
slicesToDelete := []*discovery.EndpointSlice{}
|
||||
for _, sliceName := range sliceNamesToDelete.UnsortedList() {
|
||||
slicesToDelete = append(slicesToDelete, slicesByName[sliceName])
|
||||
}
|
||||
|
||||
return slicesToCreate, slicesToUpdate, slicesToDelete, numAdded, numRemoved
|
||||
}
|
||||
|
||||
func (r *reconciler) deleteService(namespace, name string) {
|
||||
|
@ -18,6 +18,8 @@ package endpointslice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -65,11 +67,14 @@ func TestReconcileEmpty(t *testing.T) {
|
||||
// Given a single pod matching a service selector and no existing endpoint slices,
|
||||
// a slice should be created
|
||||
func TestReconcile1Pod(t *testing.T) {
|
||||
client := newClientset()
|
||||
setupMetrics()
|
||||
namespace := "test"
|
||||
svc, _ := newServiceAndEndpointMeta("foo", namespace)
|
||||
ipv6Family := corev1.IPv6Protocol
|
||||
svcv4, _ := newServiceAndEndpointMeta("foo", namespace)
|
||||
svcv6, _ := newServiceAndEndpointMeta("foo", namespace)
|
||||
svcv6.Spec.IPFamily = &ipv6Family
|
||||
|
||||
pod1 := newPod(1, namespace, true, 1)
|
||||
pod1.Status.PodIPs = []corev1.PodIP{{IP: "1.2.3.4"}, {IP: "1234::5678:0000:0000:9abc:def0"}}
|
||||
pod1.Spec.Hostname = "example-hostname"
|
||||
node1 := &corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -81,33 +86,92 @@ func TestReconcile1Pod(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
triggerTime := time.Now()
|
||||
r := newReconciler(client, []*corev1.Node{node1}, defaultMaxEndpointsPerSlice)
|
||||
reconcileHelper(t, r, &svc, []*corev1.Pod{pod1}, []*discovery.EndpointSlice{}, triggerTime)
|
||||
assert.Len(t, client.Actions(), 1, "Expected 1 additional clientset action")
|
||||
testCases := map[string]struct {
|
||||
service corev1.Service
|
||||
expectedAddressType discovery.AddressType
|
||||
expectedEndpoint discovery.Endpoint
|
||||
}{
|
||||
"ipv4": {
|
||||
service: svcv4,
|
||||
expectedAddressType: discovery.AddressTypeIPv4,
|
||||
expectedEndpoint: discovery.Endpoint{
|
||||
Addresses: []string{"1.2.3.4"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Topology: map[string]string{
|
||||
"kubernetes.io/hostname": "node-1",
|
||||
"topology.kubernetes.io/zone": "us-central1-a",
|
||||
"topology.kubernetes.io/region": "us-central1",
|
||||
},
|
||||
TargetRef: &corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Namespace: namespace,
|
||||
Name: "pod1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"ipv6": {
|
||||
service: svcv6,
|
||||
expectedAddressType: discovery.AddressTypeIPv6,
|
||||
expectedEndpoint: discovery.Endpoint{
|
||||
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Topology: map[string]string{
|
||||
"kubernetes.io/hostname": "node-1",
|
||||
"topology.kubernetes.io/zone": "us-central1-a",
|
||||
"topology.kubernetes.io/region": "us-central1",
|
||||
},
|
||||
TargetRef: &corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Namespace: namespace,
|
||||
Name: "pod1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
slices := fetchEndpointSlices(t, client, namespace)
|
||||
assert.Len(t, slices, 1, "Expected 1 endpoint slices")
|
||||
assert.Regexp(t, "^"+svc.Name, slices[0].Name)
|
||||
assert.Equal(t, svc.Name, slices[0].Labels[discovery.LabelServiceName])
|
||||
assert.Equal(t, slices[0].Annotations, map[string]string{
|
||||
"endpoints.kubernetes.io/last-change-trigger-time": triggerTime.Format(time.RFC3339Nano),
|
||||
})
|
||||
assert.EqualValues(t, []discovery.Endpoint{{
|
||||
Addresses: []string{"1.2.3.5"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Topology: map[string]string{
|
||||
"kubernetes.io/hostname": "node-1",
|
||||
"topology.kubernetes.io/zone": "us-central1-a",
|
||||
"topology.kubernetes.io/region": "us-central1",
|
||||
},
|
||||
TargetRef: &corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Namespace: namespace,
|
||||
Name: "pod1",
|
||||
},
|
||||
}}, slices[0].Endpoints)
|
||||
expectMetrics(t, expectedMetrics{desiredSlices: 1, actualSlices: 1, desiredEndpoints: 1, addedPerSync: 1, removedPerSync: 0, numCreated: 1, numUpdated: 0, numDeleted: 0})
|
||||
for name, testCase := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
client := newClientset()
|
||||
setupMetrics()
|
||||
triggerTime := time.Now()
|
||||
r := newReconciler(client, []*corev1.Node{node1}, defaultMaxEndpointsPerSlice)
|
||||
reconcileHelper(t, r, &testCase.service, []*corev1.Pod{pod1}, []*discovery.EndpointSlice{}, triggerTime)
|
||||
|
||||
if len(client.Actions()) != 1 {
|
||||
t.Errorf("Expected 1 clientset action, got %d", len(client.Actions()))
|
||||
}
|
||||
|
||||
slices := fetchEndpointSlices(t, client, namespace)
|
||||
|
||||
if len(slices) != 1 {
|
||||
t.Fatalf("Expected 1 EndpointSlice, got %d", len(slices))
|
||||
}
|
||||
|
||||
slice := slices[0]
|
||||
if !strings.HasPrefix(slice.Name, testCase.service.Name) {
|
||||
t.Errorf("Expected EndpointSlice name to start with %s, got %s", testCase.service.Name, slice.Name)
|
||||
}
|
||||
|
||||
if slice.Labels[discovery.LabelServiceName] != testCase.service.Name {
|
||||
t.Errorf("Expected EndpointSlice to have label set with %s value, got %s", testCase.service.Name, slice.Labels[discovery.LabelServiceName])
|
||||
}
|
||||
|
||||
if slice.Annotations[corev1.EndpointsLastChangeTriggerTime] != triggerTime.Format(time.RFC3339Nano) {
|
||||
t.Errorf("Expected EndpointSlice trigger time annotation to be %s, got %s", triggerTime.Format(time.RFC3339Nano), slice.Annotations[corev1.EndpointsLastChangeTriggerTime])
|
||||
}
|
||||
|
||||
if len(slice.Endpoints) != 1 {
|
||||
t.Fatalf("Expected 1 Endpoint, got %d", len(slice.Endpoints))
|
||||
}
|
||||
|
||||
endpoint := slice.Endpoints[0]
|
||||
if !reflect.DeepEqual(endpoint, testCase.expectedEndpoint) {
|
||||
t.Errorf("Expected endpoint: %+v, got: %+v", testCase.expectedEndpoint, endpoint)
|
||||
}
|
||||
|
||||
expectMetrics(t, expectedMetrics{desiredSlices: 1, actualSlices: 1, desiredEndpoints: 1, addedPerSync: 1, removedPerSync: 0, numCreated: 1, numUpdated: 0, numDeleted: 0})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// given an existing endpoint slice and no pods matching the service, the existing
|
||||
@ -437,6 +501,56 @@ func TestReconcileEndpointSlicesUpdatePacking(t *testing.T) {
|
||||
expectUnorderedSlicesWithLengths(t, fetchEndpointSlices(t, client, namespace), []int{95, 20})
|
||||
}
|
||||
|
||||
// In this test, we want to verify that old EndpointSlices with a deprecated IP
|
||||
// address type will be replaced with a newer IPv4 type.
|
||||
func TestReconcileEndpointSlicesReplaceDeprecated(t *testing.T) {
|
||||
client := newClientset()
|
||||
setupMetrics()
|
||||
namespace := "test"
|
||||
|
||||
svc, endpointMeta := newServiceAndEndpointMeta("foo", namespace)
|
||||
endpointMeta.AddressType = discovery.AddressTypeIP
|
||||
|
||||
existingSlices := []*discovery.EndpointSlice{}
|
||||
pods := []*corev1.Pod{}
|
||||
|
||||
slice1 := newEmptyEndpointSlice(1, namespace, endpointMeta, svc)
|
||||
for i := 0; i < 80; i++ {
|
||||
pod := newPod(i, namespace, true, 1)
|
||||
slice1.Endpoints = append(slice1.Endpoints, podToEndpoint(pod, &corev1.Node{}, &corev1.Service{Spec: corev1.ServiceSpec{}}))
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
existingSlices = append(existingSlices, slice1)
|
||||
|
||||
slice2 := newEmptyEndpointSlice(2, namespace, endpointMeta, svc)
|
||||
for i := 100; i < 150; i++ {
|
||||
pod := newPod(i, namespace, true, 1)
|
||||
slice2.Endpoints = append(slice2.Endpoints, podToEndpoint(pod, &corev1.Node{}, &corev1.Service{Spec: corev1.ServiceSpec{}}))
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
existingSlices = append(existingSlices, slice2)
|
||||
|
||||
createEndpointSlices(t, client, namespace, existingSlices)
|
||||
|
||||
r := newReconciler(client, []*corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "node-1"}}}, defaultMaxEndpointsPerSlice)
|
||||
reconcileHelper(t, r, &svc, pods, existingSlices, time.Now())
|
||||
|
||||
// ensure that both original endpoint slices have been deleted
|
||||
expectActions(t, client.Actions(), 2, "delete", "endpointslices")
|
||||
|
||||
endpointSlices := fetchEndpointSlices(t, client, namespace)
|
||||
|
||||
// since this involved replacing both EndpointSlices, the result should be
|
||||
// perfectly packed.
|
||||
expectUnorderedSlicesWithLengths(t, endpointSlices, []int{100, 30})
|
||||
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
if endpointSlice.AddressType != discovery.AddressTypeIPv4 {
|
||||
t.Errorf("Expected address type to be IPv4, got %s", endpointSlice.AddressType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Named ports can map to different port numbers on different pods.
|
||||
// This test ensures that EndpointSlices are grouped correctly in that case.
|
||||
func TestReconcileEndpointSlicesNamedPorts(t *testing.T) {
|
||||
@ -489,7 +603,6 @@ func TestReconcileEndpointSlicesNamedPorts(t *testing.T) {
|
||||
|
||||
// generate data structures for expected slice ports and address types
|
||||
protoTCP := corev1.ProtocolTCP
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
expectedSlices := []discovery.EndpointSlice{}
|
||||
for i := range fetchedSlices {
|
||||
expectedSlices = append(expectedSlices, discovery.EndpointSlice{
|
||||
@ -498,7 +611,7 @@ func TestReconcileEndpointSlicesNamedPorts(t *testing.T) {
|
||||
Protocol: &protoTCP,
|
||||
Port: utilpointer.Int32Ptr(int32(8080 + i)),
|
||||
}},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/discovery/validation"
|
||||
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
||||
utilnet "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
// podEndpointChanged returns true if the results of podToEndpoint are different
|
||||
@ -70,7 +71,7 @@ func podToEndpoint(pod *corev1.Pod, node *corev1.Node, service *corev1.Service)
|
||||
|
||||
ready := service.Spec.PublishNotReadyAddresses || podutil.IsPodReady(pod)
|
||||
ep := discovery.Endpoint{
|
||||
Addresses: getEndpointAddresses(pod.Status),
|
||||
Addresses: getEndpointAddresses(pod.Status, service.Spec.IPFamily),
|
||||
Conditions: discovery.EndpointConditions{
|
||||
Ready: &ready,
|
||||
},
|
||||
@ -124,16 +125,18 @@ func getEndpointPorts(service *corev1.Service, pod *corev1.Pod) []discovery.Endp
|
||||
}
|
||||
|
||||
// getEndpointAddresses returns a list of addresses generated from a pod status.
|
||||
func getEndpointAddresses(podStatus corev1.PodStatus) []string {
|
||||
if len(podStatus.PodIPs) > 1 {
|
||||
addresss := []string{}
|
||||
for _, podIP := range podStatus.PodIPs {
|
||||
addresss = append(addresss, podIP.IP)
|
||||
func getEndpointAddresses(podStatus corev1.PodStatus, ipFamily *corev1.IPFamily) []string {
|
||||
isIPv6Family := ipFamily != nil && *ipFamily == corev1.IPv6Protocol
|
||||
addresses := []string{}
|
||||
|
||||
for _, podIP := range podStatus.PodIPs {
|
||||
isIPv6PodIP := utilnet.IsIPv6String(podIP.IP)
|
||||
if isIPv6Family == isIPv6PodIP {
|
||||
addresses = append(addresses, podIP.IP)
|
||||
}
|
||||
return addresss
|
||||
}
|
||||
|
||||
return []string{podStatus.PodIP}
|
||||
return addresses
|
||||
}
|
||||
|
||||
// endpointsEqualBeyondHash returns true if endpoints have equal attributes
|
||||
|
@ -38,12 +38,12 @@ import (
|
||||
)
|
||||
|
||||
func TestNewEndpointSlice(t *testing.T) {
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
ipAddressType := discovery.AddressTypeIPv4
|
||||
portName := "foo"
|
||||
protocol := v1.ProtocolTCP
|
||||
endpointMeta := endpointMeta{
|
||||
Ports: []discovery.EndpointPort{{Name: &portName, Protocol: &protocol}},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: ipAddressType,
|
||||
}
|
||||
service := v1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"},
|
||||
@ -204,7 +204,7 @@ func TestPodToEndpoint(t *testing.T) {
|
||||
node: node1,
|
||||
svc: &svc,
|
||||
expectedEndpoint: discovery.Endpoint{
|
||||
Addresses: []string{"1.2.3.4", "1234::5678:0000:0000:9abc:def0"},
|
||||
Addresses: []string{"1.2.3.4"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
Topology: map[string]string{
|
||||
"kubernetes.io/hostname": "node-1",
|
||||
@ -283,11 +283,11 @@ func TestPodChangedWithPodEndpointChanged(t *testing.T) {
|
||||
}
|
||||
newPod.ObjectMeta.ResourceVersion = oldPod.ObjectMeta.ResourceVersion
|
||||
|
||||
newPod.Status.PodIP = "1.2.3.1"
|
||||
newPod.Status.PodIPs = []v1.PodIP{{IP: "1.2.3.1"}}
|
||||
if !podChangedHelper(oldPod, newPod, podEndpointChanged) {
|
||||
t.Errorf("Expected pod to be changed with pod IP address change")
|
||||
}
|
||||
newPod.Status.PodIP = oldPod.Status.PodIP
|
||||
newPod.Status.PodIPs = oldPod.Status.PodIPs
|
||||
|
||||
newPod.ObjectMeta.Name = "wrong-name"
|
||||
if !podChangedHelper(oldPod, newPod, podEndpointChanged) {
|
||||
@ -333,6 +333,9 @@ func newPod(n int, namespace string, ready bool, nPorts int) *v1.Pod {
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
PodIP: fmt.Sprintf("1.2.3.%d", 4+n),
|
||||
PodIPs: []v1.PodIP{{
|
||||
IP: fmt.Sprintf("1.2.3.%d", 4+n),
|
||||
}},
|
||||
Conditions: []v1.PodCondition{
|
||||
{
|
||||
Type: v1.PodReady,
|
||||
@ -381,10 +384,10 @@ func newServiceAndEndpointMeta(name, namespace string) (v1.Service, endpointMeta
|
||||
},
|
||||
}
|
||||
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
addressType := discovery.AddressTypeIPv4
|
||||
protocol := v1.ProtocolTCP
|
||||
endpointMeta := endpointMeta{
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: addressType,
|
||||
Ports: []discovery.EndpointPort{{Name: &name, Port: &portNum, Protocol: &protocol}},
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ go_library(
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/discovery/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/utils/net:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
discoveryclient "k8s.io/client-go/kubernetes/typed/discovery/v1alpha1"
|
||||
utilnet "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
// EndpointsAdapter provides a simple interface for reading and writing both
|
||||
@ -95,6 +96,16 @@ func (adapter *EndpointsAdapter) EnsureEndpointSliceFromEndpoints(namespace stri
|
||||
return err
|
||||
}
|
||||
|
||||
// required for transition from IP to IPv4 address type.
|
||||
if currentEndpointSlice.AddressType != endpointSlice.AddressType {
|
||||
err = adapter.endpointSliceClient.EndpointSlices(namespace).Delete(endpointSlice.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = adapter.endpointSliceClient.EndpointSlices(namespace).Create(endpointSlice)
|
||||
return err
|
||||
}
|
||||
|
||||
if apiequality.Semantic.DeepEqual(currentEndpointSlice.Endpoints, endpointSlice.Endpoints) &&
|
||||
apiequality.Semantic.DeepEqual(currentEndpointSlice.Ports, endpointSlice.Ports) &&
|
||||
apiequality.Semantic.DeepEqual(currentEndpointSlice.Labels, endpointSlice.Labels) {
|
||||
@ -112,8 +123,9 @@ func endpointSliceFromEndpoints(endpoints *corev1.Endpoints) *discovery.Endpoint
|
||||
endpointSlice.Name = endpoints.Name
|
||||
endpointSlice.Labels = map[string]string{discovery.LabelServiceName: endpoints.Name}
|
||||
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
endpointSlice.AddressType = &ipAddressType
|
||||
// TODO: Add support for IPv6 addresses here (and in the rest of
|
||||
// EndpointsAdapter).
|
||||
endpointSlice.AddressType = discovery.AddressTypeIPv4
|
||||
|
||||
if len(endpoints.Subsets) > 0 {
|
||||
subset := endpoints.Subsets[0]
|
||||
@ -124,17 +136,28 @@ func endpointSliceFromEndpoints(endpoints *corev1.Endpoints) *discovery.Endpoint
|
||||
Protocol: &subset.Ports[i].Protocol,
|
||||
})
|
||||
}
|
||||
for _, address := range subset.Addresses {
|
||||
endpointSlice.Endpoints = append(endpointSlice.Endpoints, endpointFromAddress(address, true))
|
||||
}
|
||||
for _, address := range subset.NotReadyAddresses {
|
||||
endpointSlice.Endpoints = append(endpointSlice.Endpoints, endpointFromAddress(address, false))
|
||||
}
|
||||
endpointSlice.Endpoints = append(endpointSlice.Endpoints, getEndpointsFromAddresses(subset.Addresses, endpointSlice.AddressType, true)...)
|
||||
endpointSlice.Endpoints = append(endpointSlice.Endpoints, getEndpointsFromAddresses(subset.NotReadyAddresses, endpointSlice.AddressType, false)...)
|
||||
}
|
||||
|
||||
return endpointSlice
|
||||
}
|
||||
|
||||
// getEndpointsFromAddresses returns a list of Endpoints from addresses that
|
||||
// match the provided address type.
|
||||
func getEndpointsFromAddresses(addresses []corev1.EndpointAddress, addressType discovery.AddressType, ready bool) []discovery.Endpoint {
|
||||
endpoints := []discovery.Endpoint{}
|
||||
isIPv6AddressType := addressType == discovery.AddressTypeIPv6
|
||||
|
||||
for _, address := range addresses {
|
||||
if utilnet.IsIPv6String(address.IP) == isIPv6AddressType {
|
||||
endpoints = append(endpoints, endpointFromAddress(address, ready))
|
||||
}
|
||||
}
|
||||
|
||||
return endpoints
|
||||
}
|
||||
|
||||
// endpointFromAddress generates an Endpoint from an EndpointAddress resource.
|
||||
func endpointFromAddress(address corev1.EndpointAddress, ready bool) discovery.Endpoint {
|
||||
topology := map[string]string{}
|
||||
|
@ -105,6 +105,11 @@ func TestEndpointsAdapterGet(t *testing.T) {
|
||||
func TestEndpointsAdapterCreate(t *testing.T) {
|
||||
endpoints1, epSlice1 := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.3", "10.1.2.4"})
|
||||
|
||||
// even if an Endpoints resource includes an IPv6 address, it should not be
|
||||
// included in the corresponding EndpointSlice.
|
||||
endpoints2, _ := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.5", "10.1.2.6", "1234::5678:0000:0000:9abc:def0"})
|
||||
_, epSlice2 := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.5", "10.1.2.6"})
|
||||
|
||||
testCases := map[string]struct {
|
||||
endpointSlicesEnabled bool
|
||||
expectedError error
|
||||
@ -124,6 +129,15 @@ func TestEndpointsAdapterCreate(t *testing.T) {
|
||||
namespaceParam: endpoints1.Namespace,
|
||||
endpointsParam: endpoints1,
|
||||
},
|
||||
"single-endpoint-with-ipv6": {
|
||||
endpointSlicesEnabled: true,
|
||||
expectedError: nil,
|
||||
expectedEndpoints: endpoints2,
|
||||
expectedEndpointSlice: epSlice2,
|
||||
endpoints: []*corev1.Endpoints{},
|
||||
namespaceParam: endpoints2.Namespace,
|
||||
endpointsParam: endpoints2,
|
||||
},
|
||||
"single-endpoint-no-slices": {
|
||||
endpointSlicesEnabled: false,
|
||||
expectedError: nil,
|
||||
@ -199,6 +213,13 @@ func TestEndpointsAdapterUpdate(t *testing.T) {
|
||||
endpoints2, epSlice2 := generateEndpointsAndSlice("foo", "testing", []int{80, 443}, []string{"10.1.2.3", "10.1.2.4", "10.1.2.5"})
|
||||
endpoints3, _ := generateEndpointsAndSlice("bar", "testing", []int{80, 443}, []string{"10.1.2.3", "10.1.2.4", "10.1.2.5"})
|
||||
|
||||
// ensure that EndpointSlice with deprecated IP address type is replaced
|
||||
// with one that has an IPv4 address type.
|
||||
endpoints4, _ := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.7", "10.1.2.8"})
|
||||
_, epSlice4IP := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.7", "10.1.2.8"})
|
||||
epSlice4IP.AddressType = discovery.AddressTypeIP
|
||||
_, epSlice4IPv4 := generateEndpointsAndSlice("foo", "testing", []int{80}, []string{"10.1.2.7", "10.1.2.8"})
|
||||
|
||||
testCases := map[string]struct {
|
||||
endpointSlicesEnabled bool
|
||||
expectedError error
|
||||
@ -218,6 +239,16 @@ func TestEndpointsAdapterUpdate(t *testing.T) {
|
||||
namespaceParam: "testing",
|
||||
endpointsParam: endpoints1,
|
||||
},
|
||||
"existing-endpointslice-replaced-with-updated-ipv4-address-type": {
|
||||
endpointSlicesEnabled: true,
|
||||
expectedError: nil,
|
||||
expectedEndpoints: endpoints4,
|
||||
expectedEndpointSlice: epSlice4IPv4,
|
||||
endpoints: []*corev1.Endpoints{endpoints4},
|
||||
endpointSlices: []*discovery.EndpointSlice{epSlice4IP},
|
||||
namespaceParam: "testing",
|
||||
endpointsParam: endpoints4,
|
||||
},
|
||||
"add-ports-and-ips": {
|
||||
endpointSlicesEnabled: true,
|
||||
expectedError: nil,
|
||||
@ -291,9 +322,8 @@ func TestEndpointsAdapterUpdate(t *testing.T) {
|
||||
func generateEndpointsAndSlice(name, namespace string, ports []int, addresses []string) (*corev1.Endpoints, *discovery.EndpointSlice) {
|
||||
objectMeta := metav1.ObjectMeta{Name: name, Namespace: namespace}
|
||||
trueBool := true
|
||||
addressTypeIP := discovery.AddressTypeIP
|
||||
|
||||
epSlice := &discovery.EndpointSlice{ObjectMeta: objectMeta, AddressType: &addressTypeIP}
|
||||
epSlice := &discovery.EndpointSlice{ObjectMeta: objectMeta, AddressType: discovery.AddressTypeIPv4}
|
||||
epSlice.Labels = map[string]string{discovery.LabelServiceName: name}
|
||||
subset := corev1.EndpointSubset{}
|
||||
|
||||
|
@ -1173,11 +1173,7 @@ func printEndpointSlice(obj *discovery.EndpointSlice, options printers.GenerateO
|
||||
row := metav1beta1.TableRow{
|
||||
Object: runtime.RawExtension{Object: obj},
|
||||
}
|
||||
addressType := "<unset>"
|
||||
if obj.AddressType != nil {
|
||||
addressType = string(*obj.AddressType)
|
||||
}
|
||||
row.Cells = append(row.Cells, obj.Name, addressType, formatDiscoveryPorts(obj.Ports), formatDiscoveryEndpoints(obj.Endpoints), translateTimestampSince(obj.CreationTimestamp))
|
||||
row.Cells = append(row.Cells, obj.Name, string(obj.AddressType), formatDiscoveryPorts(obj.Ports), formatDiscoveryEndpoints(obj.Endpoints), translateTimestampSince(obj.CreationTimestamp))
|
||||
return []metav1beta1.TableRow{row}, nil
|
||||
}
|
||||
|
||||
|
@ -4736,7 +4736,6 @@ func TestPrintEndpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintEndpointSlice(t *testing.T) {
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
tcpProtocol := api.ProtocolTCP
|
||||
|
||||
tests := []struct {
|
||||
@ -4749,7 +4748,7 @@ func TestPrintEndpointSlice(t *testing.T) {
|
||||
Name: "abcslice.123",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
|
||||
},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
@ -4760,14 +4759,14 @@ func TestPrintEndpointSlice(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
// Columns: Name, AddressType, Ports, Endpoints, Age
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"abcslice.123", "IP", "80", "10.1.2.3,2001:db8::1234:5678", "0s"}}},
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"abcslice.123", "IPv4", "80", "10.1.2.3,2001:db8::1234:5678", "0s"}}},
|
||||
}, {
|
||||
endpointSlice: discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "longerslicename.123",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
|
||||
},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv6,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
@ -4784,14 +4783,14 @@ func TestPrintEndpointSlice(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
// Columns: Name, AddressType, Ports, Endpoints, Age
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"longerslicename.123", "IP", "80,443", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"longerslicename.123", "IPv6", "80,443", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
|
||||
}, {
|
||||
endpointSlice: discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "multiportslice.123",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
|
||||
},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Ports: []discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
@ -4816,7 +4815,7 @@ func TestPrintEndpointSlice(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
// Columns: Name, AddressType, Ports, Endpoints, Age
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"multiportslice.123", "IP", "80,443,3000 + 1 more...", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
|
||||
expected: []metav1beta1.TableRow{{Cells: []interface{}{"multiportslice.123", "IPv4", "80,443,3000 + 1 more...", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,6 @@ func TestEsInfoChanged(t *testing.T) {
|
||||
}
|
||||
|
||||
func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, offset, numEndpoints, unreadyMod int, hosts []string, portNums []*int32) *discovery.EndpointSlice {
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
tcpProtocol := v1.ProtocolTCP
|
||||
|
||||
endpointSlice := &discovery.EndpointSlice{
|
||||
@ -346,7 +345,7 @@ func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, of
|
||||
Labels: map[string]string{discovery.LabelServiceName: serviceName},
|
||||
},
|
||||
Ports: []discovery.EndpointPort{},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Endpoints: []discovery.Endpoint{},
|
||||
}
|
||||
|
||||
|
@ -2390,7 +2390,6 @@ COMMIT
|
||||
},
|
||||
})
|
||||
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
tcpProtocol := v1.ProtocolTCP
|
||||
endpointSlice := &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -2403,7 +2402,7 @@ COMMIT
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
Protocol: &tcpProtocol,
|
||||
}},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: []string{"10.0.1.1"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
|
@ -3713,7 +3713,6 @@ func TestEndpointSliceE2E(t *testing.T) {
|
||||
})
|
||||
|
||||
// Add initial endpoint slice
|
||||
ipAddressType := discovery.AddressTypeIP
|
||||
tcpProtocol := v1.ProtocolTCP
|
||||
endpointSlice := &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -3726,7 +3725,7 @@ func TestEndpointSliceE2E(t *testing.T) {
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
Protocol: &tcpProtocol,
|
||||
}},
|
||||
AddressType: &ipAddressType,
|
||||
AddressType: discovery.AddressTypeIPv4,
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: []string{"10.0.1.1"},
|
||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
||||
|
@ -72,7 +72,7 @@ func (endpointSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
|
||||
// Validate validates a new EndpointSlice.
|
||||
func (endpointSliceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
endpointSlice := obj.(*discovery.EndpointSlice)
|
||||
err := validation.ValidateEndpointSlice(endpointSlice)
|
||||
err := validation.ValidateEndpointSliceCreate(endpointSlice)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -200,54 +200,54 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_772f83c5b34e07a5 = []byte{
|
||||
// 744 bytes of a gzipped FileDescriptorProto
|
||||
// 746 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4b, 0x6f, 0xd3, 0x4a,
|
||||
0x14, 0x8e, 0x9b, 0x5a, 0xb2, 0x27, 0x8d, 0x6e, 0x3b, 0xba, 0x8b, 0x28, 0xf7, 0x5e, 0x3b, 0xca,
|
||||
0x5d, 0x10, 0xa9, 0x30, 0x26, 0x15, 0x45, 0x15, 0x6c, 0xa8, 0x51, 0x79, 0x48, 0x3c, 0xc2, 0xd0,
|
||||
0x05, 0x42, 0x2c, 0x98, 0xd8, 0x53, 0xc7, 0x24, 0xf1, 0x58, 0xf6, 0x24, 0x52, 0x76, 0xfc, 0x04,
|
||||
0x7e, 0x10, 0x4b, 0x84, 0xba, 0xec, 0xb2, 0x2b, 0x43, 0xcd, 0xbf, 0xe8, 0x0a, 0xcd, 0xf8, 0x95,
|
||||
0x12, 0x1e, 0xd9, 0xcd, 0x7c, 0x73, 0xbe, 0xef, 0x9c, 0xf3, 0xcd, 0x39, 0xe0, 0xc1, 0xf8, 0x20,
|
||||
0x46, 0x3e, 0xb3, 0xc6, 0xb3, 0x21, 0x8d, 0x02, 0xca, 0x69, 0x6c, 0xcd, 0x69, 0xe0, 0xb2, 0xc8,
|
||||
0xca, 0x1f, 0x48, 0xe8, 0x5b, 0xae, 0x1f, 0x3b, 0x6c, 0x4e, 0xa3, 0x85, 0x35, 0xef, 0x93, 0x49,
|
||||
0x38, 0x22, 0x7d, 0xcb, 0xa3, 0x01, 0x8d, 0x08, 0xa7, 0x2e, 0x0a, 0x23, 0xc6, 0x19, 0xfc, 0x2f,
|
||||
0x0b, 0x47, 0x24, 0xf4, 0x51, 0x19, 0x8e, 0x8a, 0xf0, 0xf6, 0x0d, 0xcf, 0xe7, 0xa3, 0xd9, 0x10,
|
||||
0x39, 0x6c, 0x6a, 0x79, 0xcc, 0x63, 0x96, 0x64, 0x0d, 0x67, 0x27, 0xf2, 0x26, 0x2f, 0xf2, 0x94,
|
||||
0xa9, 0xb5, 0xbb, 0x4b, 0xc9, 0x1d, 0x16, 0x51, 0x6b, 0xbe, 0x92, 0xb1, 0x7d, 0xab, 0x8a, 0x99,
|
||||
0x12, 0x67, 0xe4, 0x07, 0xa2, 0xbe, 0x70, 0xec, 0x09, 0x20, 0xb6, 0xa6, 0x94, 0x93, 0x9f, 0xb1,
|
||||
0xac, 0x5f, 0xb1, 0xa2, 0x59, 0xc0, 0xfd, 0x29, 0x5d, 0x21, 0xdc, 0xfe, 0x13, 0x21, 0x76, 0x46,
|
||||
0x74, 0x4a, 0x7e, 0xe4, 0x75, 0x3f, 0xd6, 0x81, 0x76, 0x14, 0xb8, 0x21, 0xf3, 0x03, 0x0e, 0x77,
|
||||
0x81, 0x4e, 0x5c, 0x37, 0xa2, 0x71, 0x4c, 0xe3, 0x96, 0xd2, 0xa9, 0xf7, 0x74, 0xbb, 0x99, 0x26,
|
||||
0xa6, 0x7e, 0x58, 0x80, 0xb8, 0x7a, 0x87, 0x14, 0x00, 0x87, 0x05, 0xae, 0xcf, 0x7d, 0x16, 0xc4,
|
||||
0xad, 0x8d, 0x8e, 0xd2, 0x6b, 0xec, 0xf5, 0xd1, 0x6f, 0xfd, 0x45, 0x45, 0xa6, 0xfb, 0x25, 0xd1,
|
||||
0x86, 0xa7, 0x89, 0x59, 0x4b, 0x13, 0x13, 0x54, 0x18, 0x5e, 0x12, 0x86, 0x3d, 0xa0, 0x8d, 0x58,
|
||||
0xcc, 0x03, 0x32, 0xa5, 0xad, 0x7a, 0x47, 0xe9, 0xe9, 0xf6, 0x56, 0x9a, 0x98, 0xda, 0xa3, 0x1c,
|
||||
0xc3, 0xe5, 0x2b, 0x1c, 0x00, 0x9d, 0x93, 0xc8, 0xa3, 0x1c, 0xd3, 0x93, 0xd6, 0xa6, 0xac, 0xe7,
|
||||
0xff, 0xe5, 0x7a, 0xc4, 0x0f, 0xa1, 0x79, 0x1f, 0x3d, 0x1f, 0xbe, 0xa3, 0x8e, 0x08, 0xa2, 0x11,
|
||||
0x0d, 0x1c, 0x9a, 0xb5, 0x78, 0x5c, 0x30, 0x71, 0x25, 0x02, 0x1d, 0xa0, 0x71, 0x16, 0xb2, 0x09,
|
||||
0xf3, 0x16, 0x2d, 0xb5, 0x53, 0xef, 0x35, 0xf6, 0xf6, 0xd7, 0x6c, 0x10, 0x1d, 0xe7, 0xbc, 0xa3,
|
||||
0x80, 0x47, 0x0b, 0x7b, 0x3b, 0x6f, 0x52, 0x2b, 0x60, 0x5c, 0x0a, 0xb7, 0xef, 0x82, 0xe6, 0x95,
|
||||
0x60, 0xb8, 0x0d, 0xea, 0x63, 0xba, 0x68, 0x29, 0xa2, 0x59, 0x2c, 0x8e, 0xf0, 0x6f, 0xa0, 0xce,
|
||||
0xc9, 0x64, 0x46, 0xa5, 0xcb, 0x3a, 0xce, 0x2e, 0x77, 0x36, 0x0e, 0x94, 0xee, 0x3e, 0x80, 0xab,
|
||||
0x9e, 0x42, 0x13, 0xa8, 0x11, 0x25, 0x6e, 0xa6, 0xa1, 0xd9, 0x7a, 0x9a, 0x98, 0x2a, 0x16, 0x00,
|
||||
0xce, 0xf0, 0xee, 0x67, 0x05, 0x6c, 0x15, 0xbc, 0x01, 0x8b, 0x38, 0xfc, 0x17, 0x6c, 0x4a, 0x87,
|
||||
0x65, 0x52, 0x5b, 0x4b, 0x13, 0x73, 0xf3, 0x99, 0x70, 0x57, 0xa2, 0xf0, 0x21, 0xd0, 0xe4, 0xb4,
|
||||
0x38, 0x6c, 0x92, 0x95, 0x60, 0xef, 0x8a, 0x66, 0x06, 0x39, 0x76, 0x99, 0x98, 0xff, 0xac, 0x6e,
|
||||
0x02, 0x2a, 0x9e, 0x71, 0x49, 0x16, 0x69, 0x42, 0x16, 0x71, 0xf9, 0x91, 0x6a, 0x96, 0x46, 0xa4,
|
||||
0xc7, 0x12, 0x85, 0x7d, 0xd0, 0x20, 0x61, 0x58, 0xd0, 0xe4, 0x17, 0xea, 0xf6, 0x5f, 0x69, 0x62,
|
||||
0x36, 0x0e, 0x2b, 0x18, 0x2f, 0xc7, 0x74, 0xbf, 0x6c, 0x80, 0x66, 0xd1, 0xc8, 0xcb, 0x89, 0xef,
|
||||
0x50, 0xf8, 0x16, 0x68, 0x62, 0xa9, 0x5c, 0xc2, 0x89, 0xec, 0xa6, 0xb1, 0x77, 0x73, 0xe9, 0xcf,
|
||||
0xca, 0xdd, 0x40, 0xe1, 0xd8, 0x13, 0x40, 0x8c, 0x44, 0x74, 0x35, 0x16, 0x4f, 0x29, 0x27, 0xd5,
|
||||
0x4c, 0x56, 0x18, 0x2e, 0x55, 0xe1, 0x3d, 0xd0, 0xc8, 0xb7, 0xe0, 0x78, 0x11, 0xd2, 0xbc, 0x4c,
|
||||
0x43, 0x96, 0x59, 0xc1, 0x97, 0x57, 0xaf, 0x78, 0x99, 0x02, 0x5f, 0x01, 0x9d, 0xe6, 0x45, 0x8b,
|
||||
0xcd, 0x11, 0x83, 0x75, 0x6d, 0xcd, 0xc1, 0xb2, 0x77, 0xf2, 0xda, 0xf4, 0x02, 0x89, 0x71, 0x25,
|
||||
0x06, 0x07, 0x40, 0x15, 0x56, 0xc6, 0xad, 0xba, 0x54, 0xdd, 0x5d, 0x53, 0x55, 0x7c, 0x82, 0xdd,
|
||||
0xcc, 0x95, 0x55, 0x71, 0x8b, 0x71, 0x26, 0xd4, 0xfd, 0xa4, 0x80, 0x9d, 0x2b, 0x0e, 0x3f, 0xf1,
|
||||
0x63, 0x0e, 0xdf, 0xac, 0xb8, 0x8c, 0xd6, 0x73, 0x59, 0xb0, 0xa5, 0xc7, 0xe5, 0x4a, 0x14, 0xc8,
|
||||
0x92, 0xc3, 0x2f, 0x80, 0xea, 0x73, 0x3a, 0x2d, 0xbc, 0xb9, 0xbe, 0x66, 0x17, 0xb2, 0xbc, 0xaa,
|
||||
0x8d, 0xc7, 0x42, 0x02, 0x67, 0x4a, 0x36, 0x3a, 0xbd, 0x30, 0x6a, 0x67, 0x17, 0x46, 0xed, 0xfc,
|
||||
0xc2, 0xa8, 0xbd, 0x4f, 0x0d, 0xe5, 0x34, 0x35, 0x94, 0xb3, 0xd4, 0x50, 0xce, 0x53, 0x43, 0xf9,
|
||||
0x9a, 0x1a, 0xca, 0x87, 0x6f, 0x46, 0xed, 0xb5, 0x56, 0x68, 0x7e, 0x0f, 0x00, 0x00, 0xff, 0xff,
|
||||
0x99, 0xbb, 0x72, 0xd7, 0x71, 0x06, 0x00, 0x00,
|
||||
0x5d, 0x10, 0xa9, 0x30, 0x26, 0x15, 0x45, 0x15, 0xac, 0x6a, 0x28, 0x0f, 0x89, 0x47, 0x18, 0xba,
|
||||
0x40, 0x88, 0x05, 0x13, 0x7b, 0xea, 0x98, 0x24, 0x1e, 0xcb, 0x9e, 0x44, 0xca, 0x8e, 0x9f, 0xc0,
|
||||
0x0f, 0x62, 0x89, 0x50, 0x97, 0x5d, 0x76, 0x65, 0x51, 0xf7, 0x5f, 0x74, 0x85, 0x66, 0xfc, 0x4a,
|
||||
0x09, 0x8f, 0xec, 0x66, 0xbe, 0x39, 0xdf, 0x77, 0xce, 0xf9, 0xe6, 0x1c, 0xf0, 0x68, 0x7c, 0x10,
|
||||
0x23, 0x9f, 0x59, 0xe3, 0xd9, 0x90, 0x46, 0x01, 0xe5, 0x34, 0xb6, 0xe6, 0x34, 0x70, 0x59, 0x64,
|
||||
0xe5, 0x0f, 0x24, 0xf4, 0x2d, 0xd7, 0x8f, 0x1d, 0x36, 0xa7, 0xd1, 0xc2, 0x9a, 0xf7, 0xc9, 0x24,
|
||||
0x1c, 0x91, 0xbe, 0xe5, 0xd1, 0x80, 0x46, 0x84, 0x53, 0x17, 0x85, 0x11, 0xe3, 0x0c, 0xfe, 0x97,
|
||||
0x85, 0x23, 0x12, 0xfa, 0xa8, 0x0c, 0x47, 0x45, 0x78, 0xfb, 0x96, 0xe7, 0xf3, 0xd1, 0x6c, 0x88,
|
||||
0x1c, 0x36, 0xb5, 0x3c, 0xe6, 0x31, 0x4b, 0xb2, 0x86, 0xb3, 0x13, 0x79, 0x93, 0x17, 0x79, 0xca,
|
||||
0xd4, 0xda, 0xdd, 0xa5, 0xe4, 0x0e, 0x8b, 0xa8, 0x35, 0x5f, 0xc9, 0xd8, 0xbe, 0x53, 0xc5, 0x4c,
|
||||
0x89, 0x33, 0xf2, 0x03, 0x51, 0x5f, 0x38, 0xf6, 0x04, 0x10, 0x5b, 0x53, 0xca, 0xc9, 0xcf, 0x58,
|
||||
0xd6, 0xaf, 0x58, 0xd1, 0x2c, 0xe0, 0xfe, 0x94, 0xae, 0x10, 0xee, 0xfe, 0x89, 0x10, 0x3b, 0x23,
|
||||
0x3a, 0x25, 0x3f, 0xf2, 0xba, 0x9f, 0xeb, 0x40, 0x3b, 0x0a, 0xdc, 0x90, 0xf9, 0x01, 0x87, 0xbb,
|
||||
0x40, 0x27, 0xae, 0x1b, 0xd1, 0x38, 0xa6, 0x71, 0x4b, 0xe9, 0xd4, 0x7b, 0xba, 0xdd, 0x4c, 0x13,
|
||||
0x53, 0x3f, 0x2c, 0x40, 0x5c, 0xbd, 0x43, 0x0a, 0x80, 0xc3, 0x02, 0xd7, 0xe7, 0x3e, 0x0b, 0xe2,
|
||||
0xd6, 0x46, 0x47, 0xe9, 0x35, 0xf6, 0xfa, 0xe8, 0xb7, 0xfe, 0xa2, 0x22, 0xd3, 0x83, 0x92, 0x68,
|
||||
0xc3, 0xd3, 0xc4, 0xac, 0xa5, 0x89, 0x09, 0x2a, 0x0c, 0x2f, 0x09, 0xc3, 0x1e, 0xd0, 0x46, 0x2c,
|
||||
0xe6, 0x01, 0x99, 0xd2, 0x56, 0xbd, 0xa3, 0xf4, 0x74, 0x7b, 0x2b, 0x4d, 0x4c, 0xed, 0x49, 0x8e,
|
||||
0xe1, 0xf2, 0x15, 0x0e, 0x80, 0xce, 0x49, 0xe4, 0x51, 0x8e, 0xe9, 0x49, 0x6b, 0x53, 0xd6, 0xf3,
|
||||
0xff, 0x72, 0x3d, 0xe2, 0x87, 0xd0, 0xbc, 0x8f, 0x5e, 0x0e, 0x3f, 0x50, 0x47, 0x04, 0xd1, 0x88,
|
||||
0x06, 0x0e, 0xcd, 0x5a, 0x3c, 0x2e, 0x98, 0xb8, 0x12, 0x81, 0x0e, 0xd0, 0x38, 0x0b, 0xd9, 0x84,
|
||||
0x79, 0x8b, 0x96, 0xda, 0xa9, 0xf7, 0x1a, 0x7b, 0xfb, 0x6b, 0x36, 0x88, 0x8e, 0x73, 0xde, 0x51,
|
||||
0xc0, 0xa3, 0x85, 0xbd, 0x9d, 0x37, 0xa9, 0x15, 0x30, 0x2e, 0x85, 0xdb, 0xf7, 0x41, 0xf3, 0x5a,
|
||||
0x30, 0xdc, 0x06, 0xf5, 0x31, 0x5d, 0xb4, 0x14, 0xd1, 0x2c, 0x16, 0x47, 0xf8, 0x37, 0x50, 0xe7,
|
||||
0x64, 0x32, 0xa3, 0xd2, 0x65, 0x1d, 0x67, 0x97, 0x7b, 0x1b, 0x07, 0x4a, 0x77, 0x1f, 0xc0, 0x55,
|
||||
0x4f, 0xa1, 0x09, 0xd4, 0x88, 0x12, 0x37, 0xd3, 0xd0, 0x6c, 0x3d, 0x4d, 0x4c, 0x15, 0x0b, 0x00,
|
||||
0x67, 0x78, 0xf7, 0xab, 0x02, 0xb6, 0x0a, 0xde, 0x80, 0x45, 0x1c, 0xfe, 0x0b, 0x36, 0xa5, 0xc3,
|
||||
0x32, 0xa9, 0xad, 0xa5, 0x89, 0xb9, 0xf9, 0x42, 0xb8, 0x2b, 0x51, 0xf8, 0x18, 0x68, 0x72, 0x5a,
|
||||
0x1c, 0x36, 0xc9, 0x4a, 0xb0, 0x77, 0x45, 0x33, 0x83, 0x1c, 0xbb, 0x4a, 0xcc, 0x7f, 0x56, 0x37,
|
||||
0x01, 0x15, 0xcf, 0xb8, 0x24, 0x8b, 0x34, 0x21, 0x8b, 0xb8, 0xfc, 0x48, 0x35, 0x4b, 0x23, 0xd2,
|
||||
0x63, 0x89, 0xc2, 0x3e, 0x68, 0x90, 0x30, 0x2c, 0x68, 0xf2, 0x0b, 0x75, 0xfb, 0xaf, 0x34, 0x31,
|
||||
0x1b, 0x87, 0x15, 0x8c, 0x97, 0x63, 0xba, 0x97, 0x1b, 0xa0, 0x59, 0x34, 0xf2, 0x7a, 0xe2, 0x3b,
|
||||
0x14, 0xbe, 0x07, 0x9a, 0x58, 0x2a, 0x97, 0x70, 0x22, 0xbb, 0x69, 0xec, 0xdd, 0x5e, 0xfa, 0xb3,
|
||||
0x72, 0x37, 0x50, 0x38, 0xf6, 0x04, 0x10, 0x23, 0x11, 0x5d, 0x8d, 0xc5, 0x73, 0xca, 0x49, 0x35,
|
||||
0x93, 0x15, 0x86, 0x4b, 0x55, 0xf8, 0x10, 0x34, 0xf2, 0x2d, 0x38, 0x5e, 0x84, 0x34, 0x2f, 0xb3,
|
||||
0x9b, 0x53, 0x1a, 0x87, 0xd5, 0xd3, 0xd5, 0xf5, 0x2b, 0x5e, 0xa6, 0xc1, 0x37, 0x40, 0xa7, 0x79,
|
||||
0xe1, 0x62, 0x7b, 0xc4, 0x70, 0xdd, 0x58, 0x73, 0xb8, 0xec, 0x9d, 0x3c, 0x99, 0x5e, 0x20, 0x31,
|
||||
0xae, 0xc4, 0xe0, 0x00, 0xa8, 0xc2, 0xce, 0xb8, 0x55, 0x97, 0xaa, 0xbb, 0x6b, 0xaa, 0x8a, 0x8f,
|
||||
0xb0, 0x9b, 0xb9, 0xb2, 0x2a, 0x6e, 0x31, 0xce, 0x84, 0xba, 0x5f, 0x14, 0xb0, 0x73, 0xcd, 0xe5,
|
||||
0x67, 0x7e, 0xcc, 0xe1, 0xbb, 0x15, 0xa7, 0xd1, 0x7a, 0x4e, 0x0b, 0xb6, 0xf4, 0xb9, 0x5c, 0x8b,
|
||||
0x02, 0x59, 0x72, 0xf9, 0x15, 0x50, 0x7d, 0x4e, 0xa7, 0x85, 0x37, 0x37, 0xd7, 0xec, 0x42, 0x96,
|
||||
0x57, 0xb5, 0xf1, 0x54, 0x48, 0xe0, 0x4c, 0xc9, 0x46, 0xa7, 0x17, 0x46, 0xed, 0xec, 0xc2, 0xa8,
|
||||
0x9d, 0x5f, 0x18, 0xb5, 0x8f, 0xa9, 0xa1, 0x9c, 0xa6, 0x86, 0x72, 0x96, 0x1a, 0xca, 0x79, 0x6a,
|
||||
0x28, 0xdf, 0x52, 0x43, 0xf9, 0x74, 0x69, 0xd4, 0xde, 0x6a, 0x85, 0xe6, 0xf7, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0x65, 0x85, 0x5a, 0x9b, 0x75, 0x06, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Endpoint) Marshal() (dAtA []byte, err error) {
|
||||
@ -437,13 +437,11 @@ func (m *EndpointSlice) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.AddressType != nil {
|
||||
i -= len(*m.AddressType)
|
||||
copy(dAtA[i:], *m.AddressType)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.AddressType)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
i -= len(m.AddressType)
|
||||
copy(dAtA[i:], m.AddressType)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(m.AddressType)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
if len(m.Ports) > 0 {
|
||||
for iNdEx := len(m.Ports) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
@ -632,10 +630,8 @@ func (m *EndpointSlice) Size() (n int) {
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.AddressType != nil {
|
||||
l = len(*m.AddressType)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
l = len(m.AddressType)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
@ -727,7 +723,7 @@ func (this *EndpointSlice) String() string {
|
||||
`ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v11.ObjectMeta", 1), `&`, ``, 1) + `,`,
|
||||
`Endpoints:` + repeatedStringForEndpoints + `,`,
|
||||
`Ports:` + repeatedStringForPorts + `,`,
|
||||
`AddressType:` + valueToStringGenerated(this.AddressType) + `,`,
|
||||
`AddressType:` + fmt.Sprintf("%v", this.AddressType) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@ -1476,8 +1472,7 @@ func (m *EndpointSlice) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := AddressType(dAtA[iNdEx:postIndex])
|
||||
m.AddressType = &s
|
||||
m.AddressType = AddressType(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
|
@ -32,12 +32,10 @@ option go_package = "v1alpha1";
|
||||
// Endpoint represents a single logical "backend" implementing a service.
|
||||
message Endpoint {
|
||||
// addresses of this endpoint. The contents of this field are interpreted
|
||||
// according to the corresponding EndpointSlice addressType field. This
|
||||
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||
// kube-proxy) must handle different types of addresses in the context of
|
||||
// their own capabilities. This must contain at least one address but no
|
||||
// more than 100.
|
||||
// according to the corresponding EndpointSlice addressType field. Consumers
|
||||
// must handle different types of addresses in the context of their own
|
||||
// capabilities. This must contain at least one address but no more than
|
||||
// 100.
|
||||
// +listType=set
|
||||
repeated string addresses = 1;
|
||||
|
||||
@ -123,13 +121,12 @@ message EndpointSlice {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// addressType specifies the type of address carried by this EndpointSlice.
|
||||
// All addresses in this slice must be the same type. The following address
|
||||
// types are currently supported:
|
||||
// * IP: Represents an IP Address. This can include both IPv4 and IPv6
|
||||
// addresses.
|
||||
// All addresses in this slice must be the same type. This field is
|
||||
// immutable after creation. The following address types are currently
|
||||
// supported:
|
||||
// * IPv4: Represents an IPv4 Address.
|
||||
// * IPv6: Represents an IPv6 Address.
|
||||
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||
// Default is IP
|
||||
// +optional
|
||||
optional string addressType = 4;
|
||||
|
||||
// endpoints is a list of unique endpoints in this slice. Each slice may
|
||||
|
@ -33,14 +33,13 @@ type EndpointSlice struct {
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
// addressType specifies the type of address carried by this EndpointSlice.
|
||||
// All addresses in this slice must be the same type. The following address
|
||||
// types are currently supported:
|
||||
// * IP: Represents an IP Address. This can include both IPv4 and IPv6
|
||||
// addresses.
|
||||
// All addresses in this slice must be the same type. This field is
|
||||
// immutable after creation. The following address types are currently
|
||||
// supported:
|
||||
// * IPv4: Represents an IPv4 Address.
|
||||
// * IPv6: Represents an IPv6 Address.
|
||||
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||
// Default is IP
|
||||
// +optional
|
||||
AddressType *AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"`
|
||||
AddressType AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"`
|
||||
// endpoints is a list of unique endpoints in this slice. Each slice may
|
||||
// include a maximum of 1000 endpoints.
|
||||
// +listType=atomic
|
||||
@ -59,22 +58,27 @@ type EndpointSlice struct {
|
||||
type AddressType string
|
||||
|
||||
const (
|
||||
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||
// addresses.
|
||||
// AddressTypeIP represents an IP Address.
|
||||
// This address type has been deprecated and has been replaced by the IPv4
|
||||
// and IPv6 adddress types. New resources with this address type will be
|
||||
// considered invalid. This will be fully removed in 1.18.
|
||||
// +deprecated
|
||||
AddressTypeIP = AddressType("IP")
|
||||
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||
// AddressTypeIPv4 represents an IPv4 Address.
|
||||
AddressTypeIPv4 = AddressType(v1.IPv4Protocol)
|
||||
// AddressTypeIPv6 represents an IPv6 Address.
|
||||
AddressTypeIPv6 = AddressType(v1.IPv6Protocol)
|
||||
// AddressTypeFQDN represents a FQDN.
|
||||
AddressTypeFQDN = AddressType("FQDN")
|
||||
)
|
||||
|
||||
// Endpoint represents a single logical "backend" implementing a service.
|
||||
type Endpoint struct {
|
||||
// addresses of this endpoint. The contents of this field are interpreted
|
||||
// according to the corresponding EndpointSlice addressType field. This
|
||||
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||
// kube-proxy) must handle different types of addresses in the context of
|
||||
// their own capabilities. This must contain at least one address but no
|
||||
// more than 100.
|
||||
// according to the corresponding EndpointSlice addressType field. Consumers
|
||||
// must handle different types of addresses in the context of their own
|
||||
// capabilities. This must contain at least one address but no more than
|
||||
// 100.
|
||||
// +listType=set
|
||||
Addresses []string `json:"addresses" protobuf:"bytes,1,rep,name=addresses"`
|
||||
// conditions contains information about the current status of the endpoint.
|
||||
|
@ -29,7 +29,7 @@ package v1alpha1
|
||||
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
|
||||
var map_Endpoint = map[string]string{
|
||||
"": "Endpoint represents a single logical \"backend\" implementing a service.",
|
||||
"addresses": "addresses of this endpoint. The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. This allows for cases like dual-stack networking where both IPv4 and IPv6 addresses would be included with the IP addressType. Consumers (e.g. kube-proxy) must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100.",
|
||||
"addresses": "addresses of this endpoint. The contents of this field are interpreted according to the corresponding EndpointSlice addressType field. Consumers must handle different types of addresses in the context of their own capabilities. This must contain at least one address but no more than 100.",
|
||||
"conditions": "conditions contains information about the current status of the endpoint.",
|
||||
"hostname": "hostname of this endpoint. This field may be used by consumers of endpoints to distinguish endpoints from each other (e.g. in DNS names). Multiple endpoints which use the same hostname should be considered fungible (e.g. multiple A values in DNS). Must pass DNS Label (RFC 1123) validation.",
|
||||
"targetRef": "targetRef is a reference to a Kubernetes object that represents this endpoint.",
|
||||
@ -64,7 +64,7 @@ func (EndpointPort) SwaggerDoc() map[string]string {
|
||||
var map_EndpointSlice = map[string]string{
|
||||
"": "EndpointSlice represents a subset of the endpoints that implement a service. For a given service there may be multiple EndpointSlice objects, selected by labels, which must be joined to produce the full set of endpoints.",
|
||||
"metadata": "Standard object's metadata.",
|
||||
"addressType": "addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. The following address types are currently supported: * IP: Represents an IP Address. This can include both IPv4 and IPv6\n addresses.\n* FQDN: Represents a Fully Qualified Domain Name. Default is IP",
|
||||
"addressType": "addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. This field is immutable after creation. The following address types are currently supported: * IPv4: Represents an IPv4 Address. * IPv6: Represents an IPv6 Address. * FQDN: Represents a Fully Qualified Domain Name.",
|
||||
"endpoints": "endpoints is a list of unique endpoints in this slice. Each slice may include a maximum of 1000 endpoints.",
|
||||
"ports": "ports specifies the list of network ports exposed by each endpoint in this slice. Each port must have a unique name. When ports is empty, it indicates that there are no defined ports. When a port is defined with a nil port value, it indicates \"all ports\". Each slice may include a maximum of 100 ports.",
|
||||
}
|
||||
|
@ -126,11 +126,6 @@ func (in *EndpointSlice) DeepCopyInto(out *EndpointSlice) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.AddressType != nil {
|
||||
in, out := &in.AddressType, &out.AddressType
|
||||
*out = new(AddressType)
|
||||
**out = **in
|
||||
}
|
||||
if in.Endpoints != nil {
|
||||
in, out := &in.Endpoints, &out.Endpoints
|
||||
*out = make([]Endpoint, len(*in))
|
||||
|
@ -309,6 +309,26 @@ func IsValidIP(value string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidIPv4Address tests that the argument is a valid IPv4 address.
|
||||
func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidIPv6Address tests that the argument is a valid IPv6 address.
|
||||
func IsValidIPv6Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
const percentFmt string = "[0-9]+%"
|
||||
const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'"
|
||||
|
||||
|
@ -355,6 +355,75 @@ func TestIsValidIP(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidIPv4Address(t *testing.T) {
|
||||
goodValues := []string{
|
||||
"1.1.1.1",
|
||||
"1.1.1.01",
|
||||
"255.0.0.1",
|
||||
"1.0.0.0",
|
||||
"0.0.0.0",
|
||||
}
|
||||
for _, val := range goodValues {
|
||||
if msgs := IsValidIPv4Address(field.NewPath(""), val); len(msgs) != 0 {
|
||||
t.Errorf("expected %q to be valid IPv4 address: %v", val, msgs)
|
||||
}
|
||||
}
|
||||
|
||||
badValues := []string{
|
||||
"[2001:db8:0:1]:80",
|
||||
"myhost.mydomain",
|
||||
"-1.0.0.0",
|
||||
"[2001:db8:0:1]",
|
||||
"a",
|
||||
"2001:4860:4860::8888",
|
||||
"::fff:1.1.1.1",
|
||||
"::1",
|
||||
"2a00:79e0:2:0:f1c3:e797:93c1:df80",
|
||||
"::",
|
||||
}
|
||||
for _, val := range badValues {
|
||||
if msgs := IsValidIPv4Address(field.NewPath(""), val); len(msgs) == 0 {
|
||||
t.Errorf("expected %q to be invalid IPv4 address", val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidIPv6Address(t *testing.T) {
|
||||
goodValues := []string{
|
||||
"2001:4860:4860::8888",
|
||||
"2a00:79e0:2:0:f1c3:e797:93c1:df80",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||
"::fff:1.1.1.1",
|
||||
"::1",
|
||||
"::",
|
||||
}
|
||||
|
||||
for _, val := range goodValues {
|
||||
if msgs := IsValidIPv6Address(field.NewPath(""), val); len(msgs) != 0 {
|
||||
t.Errorf("expected %q to be valid IPv6 address: %v", val, msgs)
|
||||
}
|
||||
}
|
||||
|
||||
badValues := []string{
|
||||
"1.1.1.1",
|
||||
"1.1.1.01",
|
||||
"255.0.0.1",
|
||||
"1.0.0.0",
|
||||
"0.0.0.0",
|
||||
"[2001:db8:0:1]:80",
|
||||
"myhost.mydomain",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334:2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||
"-1.0.0.0",
|
||||
"[2001:db8:0:1]",
|
||||
"a",
|
||||
}
|
||||
for _, val := range badValues {
|
||||
if msgs := IsValidIPv6Address(field.NewPath(""), val); len(msgs) == 0 {
|
||||
t.Errorf("expected %q to be invalid IPv6 address", val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsHTTPHeaderName(t *testing.T) {
|
||||
goodValues := []string{
|
||||
// Common ones
|
||||
|
@ -2644,11 +2644,7 @@ func describeEndpointSlice(eps *discoveryv1alpha1.EndpointSlice, events *corev1.
|
||||
printLabelsMultiline(w, "Labels", eps.Labels)
|
||||
printAnnotationsMultiline(w, "Annotations", eps.Annotations)
|
||||
|
||||
addressType := "<unset>"
|
||||
if eps.AddressType != nil {
|
||||
addressType = string(*eps.AddressType)
|
||||
}
|
||||
w.Write(LEVEL_0, "AddressType:\t%s\n", addressType)
|
||||
w.Write(LEVEL_0, "AddressType:\t%s\n", string(eps.AddressType))
|
||||
|
||||
if len(eps.Ports) == 0 {
|
||||
w.Write(LEVEL_0, "Ports: <unset>\n")
|
||||
|
@ -3261,7 +3261,6 @@ func TestDescribeStatefulSet(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeEndpointSlice(t *testing.T) {
|
||||
addressTypeIP := discoveryv1alpha1.AddressTypeIP
|
||||
protocolTCP := corev1.ProtocolTCP
|
||||
port80 := int32(80)
|
||||
|
||||
@ -3270,7 +3269,7 @@ func TestDescribeEndpointSlice(t *testing.T) {
|
||||
Name: "foo.123",
|
||||
Namespace: "bar",
|
||||
},
|
||||
AddressType: &addressTypeIP,
|
||||
AddressType: discoveryv1alpha1.AddressTypeIPv4,
|
||||
Endpoints: []discoveryv1alpha1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"1.2.3.4", "1.2.3.5"},
|
||||
@ -3309,7 +3308,7 @@ func TestDescribeEndpointSlice(t *testing.T) {
|
||||
Namespace: bar
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
AddressType: IP
|
||||
AddressType: IPv4
|
||||
Ports:
|
||||
Name Port Protocol
|
||||
---- ---- --------
|
||||
|
@ -1390,9 +1390,6 @@ func getStubObj(gvr schema.GroupVersionResource, resource metav1.APIResource) (*
|
||||
|
||||
func createOrGetResource(client dynamic.Interface, gvr schema.GroupVersionResource, resource metav1.APIResource) (*unstructured.Unstructured, error) {
|
||||
stubObj, err := getStubObj(gvr, resource)
|
||||
if gvr.Group == "discovery.k8s.io" {
|
||||
fmt.Printf("stubObj =====> %v\n", stubObj)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/discovery/v1alpha1
|
||||
gvr("discovery.k8s.io", "v1alpha1", "endpointslices"): {
|
||||
Stub: `{"metadata": {"name": "slice1"}, "protocol": "TCP", "ports": [], "endpoints": []}`,
|
||||
Stub: `{"metadata": {"name": "slice1"}, "addressType": "IPv4", "protocol": "TCP", "ports": [], "endpoints": []}`,
|
||||
ExpectedEtcdPath: "/registry/endpointslices/" + namespace + "/slice1",
|
||||
},
|
||||
// --
|
||||
|
Loading…
Reference in New Issue
Block a user