mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
Adding FQDN address type for EndpointSlice
This commit is contained in:
parent
cd274ff270
commit
d410bd28c3
4
api/openapi-spec/swagger.json
generated
4
api/openapi-spec/swagger.json
generated
@ -12025,7 +12025,7 @@
|
|||||||
"description": "Endpoint represents a single logical \"backend\" implementing a service.",
|
"description": "Endpoint represents a single logical \"backend\" implementing a service.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"addresses": {
|
"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 (IPv4 and IPv6) networking. 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. 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.",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -12090,7 +12090,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.",
|
"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": {
|
"properties": {
|
||||||
"addressType": {
|
"addressType": {
|
||||||
"description": "addressType specifies the type of address carried by this EndpointSlice. All addresses in this slice must be the same type. Default is IP",
|
"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",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"apiVersion": {
|
"apiVersion": {
|
||||||
|
@ -32,7 +32,11 @@ type EndpointSlice struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta
|
metav1.ObjectMeta
|
||||||
// addressType specifies the type of address carried by this EndpointSlice.
|
// addressType specifies the type of address carried by this EndpointSlice.
|
||||||
// All addresses in this slice must be the same type.
|
// 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.
|
||||||
|
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||||
// +optional
|
// +optional
|
||||||
AddressType *AddressType
|
AddressType *AddressType
|
||||||
// endpoints is a list of unique endpoints in this slice. Each slice may
|
// endpoints is a list of unique endpoints in this slice. Each slice may
|
||||||
@ -53,17 +57,21 @@ type EndpointSlice struct {
|
|||||||
type AddressType string
|
type AddressType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// AddressTypeIP represents an IP Address.
|
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||||
|
// addresses.
|
||||||
AddressTypeIP = AddressType("IP")
|
AddressTypeIP = AddressType("IP")
|
||||||
|
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||||
|
AddressTypeFQDN = AddressType("FQDN")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Endpoint represents a single logical "backend" implementing a service.
|
// Endpoint represents a single logical "backend" implementing a service.
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
// addresses of this endpoint. The contents of this field are interpreted
|
// addresses of this endpoint. The contents of this field are interpreted
|
||||||
// according to the corresponding EndpointSlice addressType field. This
|
// according to the corresponding EndpointSlice addressType field. This
|
||||||
// allows for cases like dual-stack (IPv4 and IPv6) networking. Consumers
|
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||||
// (e.g. kube-proxy) must handle different types of addresses in the context
|
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||||
// of their own capabilities. This must contain at least one address but no
|
// 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.
|
// more than 100.
|
||||||
// +listType=set
|
// +listType=set
|
||||||
Addresses []string
|
Addresses []string
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportedAddressTypes = sets.NewString(string(discovery.AddressTypeIP))
|
supportedAddressTypes = sets.NewString(string(discovery.AddressTypeIP), string(discovery.AddressTypeFQDN))
|
||||||
supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP), string(api.ProtocolSCTP))
|
supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP), string(api.ProtocolSCTP))
|
||||||
maxTopologyLabels = 16
|
maxTopologyLabels = 16
|
||||||
maxAddresses = 100
|
maxAddresses = 100
|
||||||
@ -45,6 +45,8 @@ var ValidateEndpointSliceName = apimachineryvalidation.NameIsDNSSubdomain
|
|||||||
func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) field.ErrorList {
|
func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) field.ErrorList {
|
||||||
allErrs := apivalidation.ValidateObjectMeta(&endpointSlice.ObjectMeta, true, ValidateEndpointSliceName, field.NewPath("metadata"))
|
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("")
|
addrType := discovery.AddressType("")
|
||||||
if endpointSlice.AddressType == nil {
|
if endpointSlice.AddressType == nil {
|
||||||
allErrs = append(allErrs, field.Required(field.NewPath("addressType"), ""))
|
allErrs = append(allErrs, field.Required(field.NewPath("addressType"), ""))
|
||||||
@ -52,8 +54,8 @@ func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) field.ErrorLi
|
|||||||
addrType = *endpointSlice.AddressType
|
addrType = *endpointSlice.AddressType
|
||||||
}
|
}
|
||||||
|
|
||||||
if endpointSlice.AddressType != nil && !supportedAddressTypes.Has(string(*endpointSlice.AddressType)) {
|
if !supportedAddressTypes.Has(string(addrType)) {
|
||||||
allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), *endpointSlice.AddressType, supportedAddressTypes.List()))
|
allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), addrType, supportedAddressTypes.List()))
|
||||||
}
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, validateEndpoints(endpointSlice.Endpoints, addrType, field.NewPath("endpoints"))...)
|
allErrs = append(allErrs, validateEndpoints(endpointSlice.Endpoints, addrType, field.NewPath("endpoints"))...)
|
||||||
@ -83,17 +85,20 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres
|
|||||||
idxPath := fldPath.Index(i)
|
idxPath := fldPath.Index(i)
|
||||||
addressPath := idxPath.Child("addresses")
|
addressPath := idxPath.Child("addresses")
|
||||||
|
|
||||||
if addrType == discovery.AddressTypeIP {
|
if len(endpoint.Addresses) == 0 {
|
||||||
if len(endpoint.Addresses) == 0 {
|
allErrs = append(allErrs, field.Required(addressPath, "must contain at least 1 address"))
|
||||||
allErrs = append(allErrs, field.Required(addressPath, "must contain at least 1 address"))
|
} else if len(endpoint.Addresses) > maxAddresses {
|
||||||
} else if len(endpoint.Addresses) > maxAddresses {
|
allErrs = append(allErrs, field.TooMany(addressPath, len(endpoint.Addresses), maxAddresses))
|
||||||
allErrs = append(allErrs, field.TooMany(addressPath, len(endpoint.Addresses), maxAddresses))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for i, address := range endpoint.Addresses {
|
for i, address := range endpoint.Addresses {
|
||||||
|
switch addrType {
|
||||||
|
case discovery.AddressTypeIP:
|
||||||
for _, msg := range validation.IsValidIP(address) {
|
for _, msg := range validation.IsValidIP(address) {
|
||||||
allErrs = append(allErrs, field.Invalid(addressPath.Index(i), address, msg))
|
allErrs = append(allErrs, field.Invalid(addressPath.Index(i), address, msg))
|
||||||
}
|
}
|
||||||
|
case discovery.AddressTypeFQDN:
|
||||||
|
allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,22 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"good-fqdns": {
|
||||||
|
expectedErrors: 0,
|
||||||
|
endpointSlice: &discovery.EndpointSlice{
|
||||||
|
ObjectMeta: standardMeta,
|
||||||
|
AddressType: addressTypePtr(discovery.AddressTypeFQDN),
|
||||||
|
Ports: []discovery.EndpointPort{{
|
||||||
|
Name: utilpointer.StringPtr("http"),
|
||||||
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
|
}},
|
||||||
|
Endpoints: []discovery.Endpoint{{
|
||||||
|
Addresses: []string{"foo.example.com", "example.com", "example.com.", "hyphens-are-good.example.com"},
|
||||||
Hostname: utilpointer.StringPtr("valid-123"),
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -67,7 +82,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolSCTP),
|
Protocol: protocolPtr(api.ProtocolSCTP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
Hostname: utilpointer.StringPtr("valid-123"),
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -85,7 +100,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -125,7 +140,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(maxAddresses),
|
Addresses: generateIPAddresses(maxAddresses),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -139,7 +154,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
Topology: generateTopology(maxTopologyLabels),
|
Topology: generateTopology(maxTopologyLabels),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -223,7 +238,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(0),
|
Addresses: generateIPAddresses(0),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -237,7 +252,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(maxAddresses + 1),
|
Addresses: generateIPAddresses(maxAddresses + 1),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -251,7 +266,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -265,7 +280,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
Topology: map[string]string{"--INVALID": "example"},
|
Topology: map[string]string{"--INVALID": "example"},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -280,7 +295,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
Topology: generateTopology(maxTopologyLabels + 1),
|
Topology: generateTopology(maxTopologyLabels + 1),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -295,7 +310,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
Hostname: utilpointer.StringPtr("--INVALID"),
|
Hostname: utilpointer.StringPtr("--INVALID"),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@ -313,14 +328,46 @@ func TestValidateEndpointSlice(t *testing.T) {
|
|||||||
Protocol: protocolPtr(api.ProtocolTCP),
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
}},
|
}},
|
||||||
Endpoints: []discovery.Endpoint{{
|
Endpoints: []discovery.Endpoint{{
|
||||||
Addresses: generateAddresses(1),
|
Addresses: generateIPAddresses(1),
|
||||||
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"bad-ip": {
|
||||||
|
expectedErrors: 1,
|
||||||
|
endpointSlice: &discovery.EndpointSlice{
|
||||||
|
ObjectMeta: standardMeta,
|
||||||
|
AddressType: addressTypePtr(discovery.AddressTypeIP),
|
||||||
|
Ports: []discovery.EndpointPort{{
|
||||||
|
Name: utilpointer.StringPtr("http"),
|
||||||
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
|
}},
|
||||||
|
Endpoints: []discovery.Endpoint{{
|
||||||
|
Addresses: []string{"123.456.789.012"},
|
||||||
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"bad-fqdns": {
|
||||||
|
expectedErrors: 4,
|
||||||
|
endpointSlice: &discovery.EndpointSlice{
|
||||||
|
ObjectMeta: standardMeta,
|
||||||
|
AddressType: addressTypePtr(discovery.AddressTypeFQDN),
|
||||||
|
Ports: []discovery.EndpointPort{{
|
||||||
|
Name: utilpointer.StringPtr("http"),
|
||||||
|
Protocol: protocolPtr(api.ProtocolTCP),
|
||||||
|
}},
|
||||||
|
Endpoints: []discovery.Endpoint{{
|
||||||
|
Addresses: []string{"foo.*", "FOO.example.com", "underscores_are_bad.example.com", "*.example.com"},
|
||||||
Hostname: utilpointer.StringPtr("valid-123"),
|
Hostname: utilpointer.StringPtr("valid-123"),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"empty-everything": {
|
"empty-everything": {
|
||||||
expectedErrors: 3,
|
expectedErrors: 3,
|
||||||
endpointSlice: &discovery.EndpointSlice{},
|
endpointSlice: &discovery.EndpointSlice{
|
||||||
|
AddressType: addressTypePtr(""),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +469,7 @@ func generateEndpoints(n int) []discovery.Endpoint {
|
|||||||
return endpoints
|
return endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAddresses(n int) []string {
|
func generateIPAddresses(n int) []string {
|
||||||
addresses := []string{}
|
addresses := []string{}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
addresses = append(addresses, fmt.Sprintf("10.1.2.%d", i%255))
|
addresses = append(addresses, fmt.Sprintf("10.1.2.%d", i%255))
|
||||||
|
@ -33,9 +33,10 @@ option go_package = "v1alpha1";
|
|||||||
message Endpoint {
|
message Endpoint {
|
||||||
// addresses of this endpoint. The contents of this field are interpreted
|
// addresses of this endpoint. The contents of this field are interpreted
|
||||||
// according to the corresponding EndpointSlice addressType field. This
|
// according to the corresponding EndpointSlice addressType field. This
|
||||||
// allows for cases like dual-stack (IPv4 and IPv6) networking. Consumers
|
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||||
// (e.g. kube-proxy) must handle different types of addresses in the context
|
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||||
// of their own capabilities. This must contain at least one address but no
|
// 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.
|
// more than 100.
|
||||||
// +listType=set
|
// +listType=set
|
||||||
repeated string addresses = 1;
|
repeated string addresses = 1;
|
||||||
@ -115,7 +116,11 @@ message EndpointSlice {
|
|||||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||||
|
|
||||||
// addressType specifies the type of address carried by this EndpointSlice.
|
// addressType specifies the type of address carried by this EndpointSlice.
|
||||||
// All addresses in this slice must be the same type.
|
// 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.
|
||||||
|
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||||
// Default is IP
|
// Default is IP
|
||||||
// +optional
|
// +optional
|
||||||
optional string addressType = 4;
|
optional string addressType = 4;
|
||||||
|
@ -33,7 +33,11 @@ type EndpointSlice struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
// addressType specifies the type of address carried by this EndpointSlice.
|
// addressType specifies the type of address carried by this EndpointSlice.
|
||||||
// All addresses in this slice must be the same type.
|
// 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.
|
||||||
|
// * FQDN: Represents a Fully Qualified Domain Name.
|
||||||
// Default is IP
|
// Default is IP
|
||||||
// +optional
|
// +optional
|
||||||
AddressType *AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"`
|
AddressType *AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"`
|
||||||
@ -55,17 +59,21 @@ type EndpointSlice struct {
|
|||||||
type AddressType string
|
type AddressType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// AddressTypeIP represents an IP Address.
|
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||||
|
// addresses.
|
||||||
AddressTypeIP = AddressType("IP")
|
AddressTypeIP = AddressType("IP")
|
||||||
|
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||||
|
AddressTypeFQDN = AddressType("FQDN")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Endpoint represents a single logical "backend" implementing a service.
|
// Endpoint represents a single logical "backend" implementing a service.
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
// addresses of this endpoint. The contents of this field are interpreted
|
// addresses of this endpoint. The contents of this field are interpreted
|
||||||
// according to the corresponding EndpointSlice addressType field. This
|
// according to the corresponding EndpointSlice addressType field. This
|
||||||
// allows for cases like dual-stack (IPv4 and IPv6) networking. Consumers
|
// allows for cases like dual-stack networking where both IPv4 and IPv6
|
||||||
// (e.g. kube-proxy) must handle different types of addresses in the context
|
// addresses would be included with the IP addressType. Consumers (e.g.
|
||||||
// of their own capabilities. This must contain at least one address but no
|
// 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.
|
// more than 100.
|
||||||
// +listType=set
|
// +listType=set
|
||||||
Addresses []string `json:"addresses" protobuf:"bytes,1,rep,name=addresses"`
|
Addresses []string `json:"addresses" protobuf:"bytes,1,rep,name=addresses"`
|
||||||
|
@ -29,7 +29,7 @@ package v1alpha1
|
|||||||
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
|
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
|
||||||
var map_Endpoint = map[string]string{
|
var map_Endpoint = map[string]string{
|
||||||
"": "Endpoint represents a single logical \"backend\" implementing a service.",
|
"": "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 (IPv4 and IPv6) networking. 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. 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.",
|
||||||
"conditions": "conditions contains information about the current status of the endpoint.",
|
"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.",
|
"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.",
|
"targetRef": "targetRef is a reference to a Kubernetes object that represents this endpoint.",
|
||||||
@ -63,7 +63,7 @@ func (EndpointPort) SwaggerDoc() map[string]string {
|
|||||||
var map_EndpointSlice = 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.",
|
"": "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.",
|
"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. Default is IP",
|
"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",
|
||||||
"endpoints": "endpoints is a list of unique endpoints in this slice. Each slice may include a maximum of 1000 endpoints.",
|
"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.",
|
"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.",
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,11 @@ func IsQualifiedName(value string) []string {
|
|||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFullyQualifiedName checks if the name is fully qualified.
|
// IsFullyQualifiedName checks if the name is fully qualified. This is similar
|
||||||
|
// to IsFullyQualifiedDomainName but requires a minimum of 3 segments instead of
|
||||||
|
// 2 and does not accept a trailing . as valid.
|
||||||
|
// TODO: This function is deprecated and preserved until all callers migrate to
|
||||||
|
// IsFullyQualifiedDomainName; please don't add new callers.
|
||||||
func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||||
var allErrors field.ErrorList
|
var allErrors field.ErrorList
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
@ -85,6 +89,26 @@ func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
|||||||
return allErrors
|
return allErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsFullyQualifiedDomainName checks if the domain name is fully qualified. This
|
||||||
|
// is similar to IsFullyQualifiedName but only requires a minimum of 2 segments
|
||||||
|
// instead of 3 and accepts a trailing . as valid.
|
||||||
|
func IsFullyQualifiedDomainName(fldPath *field.Path, name string) field.ErrorList {
|
||||||
|
var allErrors field.ErrorList
|
||||||
|
if len(name) == 0 {
|
||||||
|
return append(allErrors, field.Required(fldPath, ""))
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(name, ".") {
|
||||||
|
name = name[:len(name)-1]
|
||||||
|
}
|
||||||
|
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||||
|
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||||
|
}
|
||||||
|
if len(strings.Split(name, ".")) < 2 {
|
||||||
|
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least two segments separated by dots"))
|
||||||
|
}
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||||
const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||||
|
|
||||||
|
@ -477,8 +477,85 @@ func TestIsWildcardDNS1123Subdomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsFullyQualifiedDomainName(t *testing.T) {
|
||||||
|
goodValues := []string{
|
||||||
|
"a.com",
|
||||||
|
"k8s.io",
|
||||||
|
"dev.k8s.io",
|
||||||
|
"dev.k8s.io.",
|
||||||
|
"foo.example.com",
|
||||||
|
"this.is.a.really.long.fqdn",
|
||||||
|
"bbc.co.uk",
|
||||||
|
"10.0.0.1", // DNS labels can start with numbers and there is no requirement for letters.
|
||||||
|
"hyphens-are-good.k8s.io",
|
||||||
|
strings.Repeat("a", 246) + ".k8s.io",
|
||||||
|
}
|
||||||
|
for _, val := range goodValues {
|
||||||
|
if err := IsFullyQualifiedDomainName(field.NewPath(""), val).ToAggregate(); err != nil {
|
||||||
|
t.Errorf("expected no errors for %q: %v", val, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
badValues := []string{
|
||||||
|
".",
|
||||||
|
"...",
|
||||||
|
".io",
|
||||||
|
"com",
|
||||||
|
".com",
|
||||||
|
"Dev.k8s.io",
|
||||||
|
".foo.example.com",
|
||||||
|
"*.example.com",
|
||||||
|
"*.bar.com",
|
||||||
|
"*.foo.bar.com",
|
||||||
|
"underscores_are_bad.k8s.io",
|
||||||
|
"foo@bar.example.com",
|
||||||
|
"http://foo.example.com",
|
||||||
|
strings.Repeat("a", 247) + ".k8s.io",
|
||||||
|
}
|
||||||
|
for _, val := range badValues {
|
||||||
|
if err := IsFullyQualifiedDomainName(field.NewPath(""), val).ToAggregate(); err == nil {
|
||||||
|
t.Errorf("expected errors for %q", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsFullyQualifiedName(t *testing.T) {
|
func TestIsFullyQualifiedName(t *testing.T) {
|
||||||
tests := []struct {
|
goodValues := []string{
|
||||||
|
"dev.k8s.io",
|
||||||
|
"foo.example.com",
|
||||||
|
"this.is.a.really.long.fqdn",
|
||||||
|
"bbc.co.uk",
|
||||||
|
"10.0.0.1", // DNS labels can start with numbers and there is no requirement for letters.
|
||||||
|
"hyphens-are-good.k8s.io",
|
||||||
|
strings.Repeat("a", 246) + ".k8s.io",
|
||||||
|
}
|
||||||
|
for _, val := range goodValues {
|
||||||
|
if err := IsFullyQualifiedName(field.NewPath(""), val).ToAggregate(); err != nil {
|
||||||
|
t.Errorf("expected no errors for %q: %v", val, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
badValues := []string{
|
||||||
|
"...",
|
||||||
|
"dev.k8s.io.",
|
||||||
|
".io",
|
||||||
|
"Dev.k8s.io",
|
||||||
|
"k8s.io",
|
||||||
|
"*.example.com",
|
||||||
|
"*.bar.com",
|
||||||
|
"*.foo.bar.com",
|
||||||
|
"underscores_are_bad.k8s.io",
|
||||||
|
"foo@bar.example.com",
|
||||||
|
"http://foo.example.com",
|
||||||
|
strings.Repeat("a", 247) + ".k8s.io",
|
||||||
|
}
|
||||||
|
for _, val := range badValues {
|
||||||
|
if err := IsFullyQualifiedName(field.NewPath(""), val).ToAggregate(); err == nil {
|
||||||
|
t.Errorf("expected errors for %q", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageTests := []struct {
|
||||||
name string
|
name string
|
||||||
targetName string
|
targetName string
|
||||||
err string
|
err string
|
||||||
@ -488,6 +565,16 @@ func TestIsFullyQualifiedName(t *testing.T) {
|
|||||||
targetName: "k8s.io",
|
targetName: "k8s.io",
|
||||||
err: "should be a domain with at least three segments separated by dots",
|
err: "should be a domain with at least three segments separated by dots",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "name should not include scheme",
|
||||||
|
targetName: "http://foo.k8s.io",
|
||||||
|
err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "email should be invalid",
|
||||||
|
targetName: "example@foo.k8s.io",
|
||||||
|
err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "name cannot be empty",
|
name: "name cannot be empty",
|
||||||
targetName: "",
|
targetName: "",
|
||||||
@ -499,7 +586,7 @@ func TestIsFullyQualifiedName(t *testing.T) {
|
|||||||
err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters",
|
err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range messageTests {
|
||||||
err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate()
|
err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate()
|
||||||
switch {
|
switch {
|
||||||
case tc.err == "" && err != nil:
|
case tc.err == "" && err != nil:
|
||||||
|
Loading…
Reference in New Issue
Block a user