mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +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.",
|
||||
"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 (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": {
|
||||
"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.",
|
||||
"properties": {
|
||||
"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"
|
||||
},
|
||||
"apiVersion": {
|
||||
|
@ -32,7 +32,11 @@ 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.
|
||||
// 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
|
||||
AddressType *AddressType
|
||||
// endpoints is a list of unique endpoints in this slice. Each slice may
|
||||
@ -53,17 +57,21 @@ type EndpointSlice struct {
|
||||
type AddressType string
|
||||
|
||||
const (
|
||||
// AddressTypeIP represents an IP Address.
|
||||
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||
// addresses.
|
||||
AddressTypeIP = AddressType("IP")
|
||||
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||
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 (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
|
||||
// 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.
|
||||
// +listType=set
|
||||
Addresses []string
|
||||
|
@ -28,7 +28,7 @@ import (
|
||||
)
|
||||
|
||||
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))
|
||||
maxTopologyLabels = 16
|
||||
maxAddresses = 100
|
||||
@ -45,6 +45,8 @@ var ValidateEndpointSliceName = apimachineryvalidation.NameIsDNSSubdomain
|
||||
func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) 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"), ""))
|
||||
@ -52,8 +54,8 @@ func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice) field.ErrorLi
|
||||
addrType = *endpointSlice.AddressType
|
||||
}
|
||||
|
||||
if endpointSlice.AddressType != nil && !supportedAddressTypes.Has(string(*endpointSlice.AddressType)) {
|
||||
allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), *endpointSlice.AddressType, supportedAddressTypes.List()))
|
||||
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"))...)
|
||||
@ -83,17 +85,20 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres
|
||||
idxPath := fldPath.Index(i)
|
||||
addressPath := idxPath.Child("addresses")
|
||||
|
||||
if addrType == discovery.AddressTypeIP {
|
||||
if len(endpoint.Addresses) == 0 {
|
||||
allErrs = append(allErrs, field.Required(addressPath, "must contain at least 1 address"))
|
||||
} else if len(endpoint.Addresses) > maxAddresses {
|
||||
allErrs = append(allErrs, field.TooMany(addressPath, len(endpoint.Addresses), maxAddresses))
|
||||
}
|
||||
if len(endpoint.Addresses) == 0 {
|
||||
allErrs = append(allErrs, field.Required(addressPath, "must contain at least 1 address"))
|
||||
} else if 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) {
|
||||
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),
|
||||
}},
|
||||
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"),
|
||||
}},
|
||||
},
|
||||
@ -67,7 +82,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolSCTP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
Hostname: utilpointer.StringPtr("valid-123"),
|
||||
}},
|
||||
},
|
||||
@ -85,7 +100,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@ -125,7 +140,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(maxAddresses),
|
||||
Addresses: generateIPAddresses(maxAddresses),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@ -139,7 +154,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
Topology: generateTopology(maxTopologyLabels),
|
||||
}},
|
||||
},
|
||||
@ -223,7 +238,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(0),
|
||||
Addresses: generateIPAddresses(0),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@ -237,7 +252,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(maxAddresses + 1),
|
||||
Addresses: generateIPAddresses(maxAddresses + 1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@ -251,7 +266,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
}},
|
||||
},
|
||||
},
|
||||
@ -265,7 +280,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
Topology: map[string]string{"--INVALID": "example"},
|
||||
}},
|
||||
},
|
||||
@ -280,7 +295,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
Topology: generateTopology(maxTopologyLabels + 1),
|
||||
}},
|
||||
},
|
||||
@ -295,7 +310,7 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
Endpoints: []discovery.Endpoint{{
|
||||
Addresses: generateAddresses(1),
|
||||
Addresses: generateIPAddresses(1),
|
||||
Hostname: utilpointer.StringPtr("--INVALID"),
|
||||
}},
|
||||
},
|
||||
@ -313,14 +328,46 @@ func TestValidateEndpointSlice(t *testing.T) {
|
||||
Protocol: protocolPtr(api.ProtocolTCP),
|
||||
}},
|
||||
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"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
"empty-everything": {
|
||||
expectedErrors: 3,
|
||||
endpointSlice: &discovery.EndpointSlice{},
|
||||
endpointSlice: &discovery.EndpointSlice{
|
||||
AddressType: addressTypePtr(""),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -422,7 +469,7 @@ func generateEndpoints(n int) []discovery.Endpoint {
|
||||
return endpoints
|
||||
}
|
||||
|
||||
func generateAddresses(n int) []string {
|
||||
func generateIPAddresses(n int) []string {
|
||||
addresses := []string{}
|
||||
for i := 0; i < n; i++ {
|
||||
addresses = append(addresses, fmt.Sprintf("10.1.2.%d", i%255))
|
||||
|
@ -33,9 +33,10 @@ option go_package = "v1alpha1";
|
||||
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 (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
|
||||
// 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.
|
||||
// +listType=set
|
||||
repeated string addresses = 1;
|
||||
@ -115,7 +116,11 @@ 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.
|
||||
// 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
|
||||
// +optional
|
||||
optional string addressType = 4;
|
||||
|
@ -33,7 +33,11 @@ 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.
|
||||
// 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
|
||||
// +optional
|
||||
AddressType *AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"`
|
||||
@ -55,17 +59,21 @@ type EndpointSlice struct {
|
||||
type AddressType string
|
||||
|
||||
const (
|
||||
// AddressTypeIP represents an IP Address.
|
||||
// AddressTypeIP represents an IP Address. Inclusive of IPv4 and IPv6
|
||||
// addresses.
|
||||
AddressTypeIP = AddressType("IP")
|
||||
// AddressTypeFQDN represents a Fully Qualified Domain Name.
|
||||
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 (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
|
||||
// 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.
|
||||
// +listType=set
|
||||
Addresses []string `json:"addresses" protobuf:"bytes,1,rep,name=addresses"`
|
||||
|
@ -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 (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.",
|
||||
"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.",
|
||||
@ -63,7 +63,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. 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.",
|
||||
"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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
@ -85,6 +89,26 @@ func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||
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 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) {
|
||||
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
|
||||
targetName string
|
||||
err string
|
||||
@ -488,6 +565,16 @@ func TestIsFullyQualifiedName(t *testing.T) {
|
||||
targetName: "k8s.io",
|
||||
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",
|
||||
targetName: "",
|
||||
@ -499,7 +586,7 @@ func TestIsFullyQualifiedName(t *testing.T) {
|
||||
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()
|
||||
switch {
|
||||
case tc.err == "" && err != nil:
|
||||
|
Loading…
Reference in New Issue
Block a user