diff --git a/api/swagger-spec/v1.json b/api/swagger-spec/v1.json
index 2d70ff0bf19..6b73b29df62 100644
--- a/api/swagger-spec/v1.json
+++ b/api/swagger-spec/v1.json
@@ -15235,7 +15235,7 @@
"properties": {
"ip": {
"type": "string",
- "description": "The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24)."
+ "description": "The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready."
},
"targetRef": {
"$ref": "v1.ObjectReference",
diff --git a/docs/api-reference/v1/definitions.html b/docs/api-reference/v1/definitions.html
index 6ddba8c85ac..7222305a1f9 100755
--- a/docs/api-reference/v1/definitions.html
+++ b/docs/api-reference/v1/definitions.html
@@ -7685,7 +7685,7 @@ The resulting set of endpoints can be viewed as:
ip |
-The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). |
+The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready. |
true |
string |
|
diff --git a/pkg/api/types.go b/pkg/api/types.go
index 69c8a876a64..704df1dce31 100644
--- a/pkg/api/types.go
+++ b/pkg/api/types.go
@@ -1624,6 +1624,8 @@ type EndpointSubset struct {
// EndpointAddress is a tuple that describes single IP address.
type EndpointAddress struct {
// The IP of this endpoint.
+ // IPv6 is also accepted but not fully supported on all platforms. Also, certain
+ // kubernetes components, like kube-proxy, are not IPv6 ready.
// TODO: This should allow hostname or IP, see #4447.
IP string
diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go
index 517d5e6413a..bd35e0c7e2c 100644
--- a/pkg/api/v1/types.go
+++ b/pkg/api/v1/types.go
@@ -1998,6 +1998,8 @@ type EndpointAddress struct {
// The IP of this endpoint.
// May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16),
// or link-local multicast ((224.0.0.0/24).
+ // IPv6 is also accepted but not fully supported on all platforms. Also, certain
+ // kubernetes components, like kube-proxy, are not IPv6 ready.
// TODO: This should allow hostname or IP, See #4447.
IP string `json:"ip"`
diff --git a/pkg/api/v1/types_swagger_doc_generated.go b/pkg/api/v1/types_swagger_doc_generated.go
index b36490982c1..89917054750 100644
--- a/pkg/api/v1/types_swagger_doc_generated.go
+++ b/pkg/api/v1/types_swagger_doc_generated.go
@@ -333,7 +333,7 @@ func (EmptyDirVolumeSource) SwaggerDoc() map[string]string {
var map_EndpointAddress = map[string]string{
"": "EndpointAddress is a tuple that describes single IP address.",
- "ip": "The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24).",
+ "ip": "The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready.",
"targetRef": "Reference to object providing the endpoint.",
}
diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go
index 47b48afc4ec..2e3477b4495 100644
--- a/pkg/api/validation/validation.go
+++ b/pkg/api/validation/validation.go
@@ -2599,8 +2599,8 @@ func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *field.Path)
func validateEndpointAddress(address *api.EndpointAddress, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
- if !validation.IsValidIPv4(address.IP) {
- allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, "must be a valid IPv4 address"))
+ if !validation.IsValidIP(address.IP) {
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, "must be a valid IP address"))
return allErrs
}
return validateIpIsNotLinkLocalOrLoopback(address.IP, fldPath.Child("ip"))
diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go
index ac7d5b246ab..84280be5683 100644
--- a/pkg/api/validation/validation_test.go
+++ b/pkg/api/validation/validation_test.go
@@ -4909,13 +4909,13 @@ func TestValidateEndpoints(t *testing.T) {
ObjectMeta: api.ObjectMeta{Name: "mysvc", Namespace: "namespace"},
Subsets: []api.EndpointSubset{
{
- Addresses: []api.EndpointAddress{{IP: "2001:0db8:85a3:0042:1000:8a2e:0370:7334"}},
+ Addresses: []api.EndpointAddress{{IP: "[2001:0db8:85a3:0042:1000:8a2e:0370:7334]"}},
Ports: []api.EndpointPort{{Name: "a", Port: 93, Protocol: "TCP"}},
},
},
},
errorType: "FieldValueInvalid",
- errorDetail: "must be a valid IPv4 address",
+ errorDetail: "must be a valid IP address",
},
"Multiple ports, one without name": {
endpoints: api.Endpoints{
@@ -4965,7 +4965,7 @@ func TestValidateEndpoints(t *testing.T) {
},
},
errorType: "FieldValueInvalid",
- errorDetail: "must be a valid IPv4 address",
+ errorDetail: "must be a valid IP address",
},
"Port missing number": {
endpoints: api.Endpoints{
diff --git a/pkg/util/validation/validation.go b/pkg/util/validation/validation.go
index 9607293b7f0..aada3246559 100644
--- a/pkg/util/validation/validation.go
+++ b/pkg/util/validation/validation.go
@@ -155,9 +155,9 @@ func IsValidPortName(port string) bool {
return false
}
-// IsValidIPv4 tests that the argument is a valid IPv4 address.
-func IsValidIPv4(value string) bool {
- return net.ParseIP(value) != nil && net.ParseIP(value).To4() != nil
+// IsValidIP tests that the argument is a valid IP address.
+func IsValidIP(value string) bool {
+ return net.ParseIP(value) != nil
}
const percentFmt string = "[0-9]+%"
diff --git a/pkg/util/validation/validation_test.go b/pkg/util/validation/validation_test.go
index 38fc63c3f76..79967d20467 100644
--- a/pkg/util/validation/validation_test.go
+++ b/pkg/util/validation/validation_test.go
@@ -281,6 +281,11 @@ func TestIsValidLabelValue(t *testing.T) {
func TestIsValidIP(t *testing.T) {
goodValues := []string{
+ "::1",
+ "2a00:79e0:2:0:f1c3:e797:93c1:df80",
+ "::",
+ "2001:4860:4860::8888",
+ "::fff:1.1.1.1",
"1.1.1.1",
"1.1.1.01",
"255.0.0.1",
@@ -288,22 +293,20 @@ func TestIsValidIP(t *testing.T) {
"0.0.0.0",
}
for _, val := range goodValues {
- if !IsValidIPv4(val) {
+ if !IsValidIP(val) {
t.Errorf("expected true for %q", val)
}
}
badValues := []string{
- "2a00:79e0:2:0:f1c3:e797:93c1:df80", // This is valid IPv6
- "a",
+ "[2001:db8:0:1]:80",
"myhost.mydomain",
"-1.0.0.0",
- "1.0.0.256",
- "1.0.0.1.1",
- "1.0.0.1.",
+ "[2001:db8:0:1]",
+ "a",
}
for _, val := range badValues {
- if IsValidIPv4(val) {
+ if IsValidIP(val) {
t.Errorf("expected false for %q", val)
}
}