K8s SCTP support implementation for the first pull request
The requested Service Protocol is checked against the supported protocols of GCE Internal LB. The supported protocols are TCP and UDP. SCTP is not supported by OpenStack LBaaS. If SCTP is requested in a Service with type=LoadBalancer, the request is rejected. Comment style is also corrected. SCTP is not allowed for LoadBalancer Service and for HostPort. Kube-proxy can be configured not to start listening on the host port for SCTP: see the new SCTPUserSpaceNode parameter changed the vendor github.com/nokia/sctp to github.com/ishidawataru/sctp. I.e. from now on we use the upstream version. netexec.go compilation fixed. Various test cases fixed SCTP related conformance tests removed. Netexec's pod definition and Dockerfile are updated to expose the new SCTP port(8082) SCTP related e2e test cases are removed as the e2e test systems do not support SCTP sctp related firewall config is removed from cluster/gce/util.sh. Variable name sctp_addr is corrected to sctpAddr in pkg/proxy/ipvs/proxier.go cluster/gce/util.sh is copied from master
This commit is contained in:
parent
aec270256b
commit
a6da2b1472
10
api/openapi-spec/swagger.json
generated
10
api/openapi-spec/swagger.json
generated
@ -79022,7 +79022,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\".",
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\".",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79269,7 +79269,7 @@
|
|||||||
"format": "int32"
|
"format": "int32"
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"description": "The IP protocol for this port. Must be UDP or TCP. Default is TCP.",
|
"description": "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82758,7 +82758,7 @@
|
|||||||
"format": "int32"
|
"format": "int32"
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"description": "The IP protocol for this port. Supports \"TCP\" and \"UDP\". Default is TCP.",
|
"description": "The IP protocol for this port. Supports \"TCP\", \"UDP\", and \"SCTP\". Default is TCP.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"targetPort": {
|
"targetPort": {
|
||||||
@ -84254,7 +84254,7 @@
|
|||||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"description": "Optional. The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.",
|
"description": "Optional. The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84925,7 +84925,7 @@
|
|||||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"description": "The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.",
|
"description": "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
api/swagger-spec/apps_v1.json
generated
2
api/swagger-spec/apps_v1.json
generated
@ -8018,7 +8018,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/apps_v1beta1.json
generated
2
api/swagger-spec/apps_v1beta1.json
generated
@ -5626,7 +5626,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/apps_v1beta2.json
generated
2
api/swagger-spec/apps_v1beta2.json
generated
@ -8018,7 +8018,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/batch_v1.json
generated
2
api/swagger-spec/batch_v1.json
generated
@ -2933,7 +2933,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/batch_v1beta1.json
generated
2
api/swagger-spec/batch_v1beta1.json
generated
@ -2988,7 +2988,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/batch_v2alpha1.json
generated
2
api/swagger-spec/batch_v2alpha1.json
generated
@ -2988,7 +2988,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
4
api/swagger-spec/extensions_v1beta1.json
generated
4
api/swagger-spec/extensions_v1beta1.json
generated
@ -8666,7 +8666,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -10280,7 +10280,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"$ref": "v1.Protocol",
|
"$ref": "v1.Protocol",
|
||||||
"description": "Optional. The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP."
|
"description": "Optional. The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP."
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
2
api/swagger-spec/networking.k8s.io_v1.json
generated
2
api/swagger-spec/networking.k8s.io_v1.json
generated
@ -1426,7 +1426,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"$ref": "v1.Protocol",
|
"$ref": "v1.Protocol",
|
||||||
"description": "The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP."
|
"description": "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP."
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
6
api/swagger-spec/v1.json
generated
6
api/swagger-spec/v1.json
generated
@ -18480,7 +18480,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The IP protocol for this port. Must be UDP or TCP. Default is TCP."
|
"description": "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -21466,7 +21466,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"."
|
"description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\"."
|
||||||
},
|
},
|
||||||
"hostIP": {
|
"hostIP": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -23091,7 +23091,7 @@
|
|||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The IP protocol for this port. Supports \"TCP\" and \"UDP\". Default is TCP."
|
"description": "The IP protocol for this port. Supports \"TCP\", \"UDP\", and \"SCTP\". Default is TCP."
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -51,18 +51,20 @@ function config-ip-firewall {
|
|||||||
sysctl -w net.ipv4.conf.all.route_localnet=1
|
sysctl -w net.ipv4.conf.all.route_localnet=1
|
||||||
|
|
||||||
# The GCI image has host firewall which drop most inbound/forwarded packets.
|
# The GCI image has host firewall which drop most inbound/forwarded packets.
|
||||||
# We need to add rules to accept all TCP/UDP/ICMP packets.
|
# We need to add rules to accept all TCP/UDP/ICMP/SCTP packets.
|
||||||
if iptables -w -L INPUT | grep "Chain INPUT (policy DROP)" > /dev/null; then
|
if iptables -w -L INPUT | grep "Chain INPUT (policy DROP)" > /dev/null; then
|
||||||
echo "Add rules to accept all inbound TCP/UDP/ICMP packets"
|
echo "Add rules to accept all inbound TCP/UDP/ICMP packets"
|
||||||
iptables -A INPUT -w -p TCP -j ACCEPT
|
iptables -A INPUT -w -p TCP -j ACCEPT
|
||||||
iptables -A INPUT -w -p UDP -j ACCEPT
|
iptables -A INPUT -w -p UDP -j ACCEPT
|
||||||
iptables -A INPUT -w -p ICMP -j ACCEPT
|
iptables -A INPUT -w -p ICMP -j ACCEPT
|
||||||
|
iptables -A INPUT -w -p SCTP -j ACCEPT
|
||||||
fi
|
fi
|
||||||
if iptables -w -L FORWARD | grep "Chain FORWARD (policy DROP)" > /dev/null; then
|
if iptables -w -L FORWARD | grep "Chain FORWARD (policy DROP)" > /dev/null; then
|
||||||
echo "Add rules to accept all forwarded TCP/UDP/ICMP packets"
|
echo "Add rules to accept all forwarded TCP/UDP/ICMP/SCTP packets"
|
||||||
iptables -A FORWARD -w -p TCP -j ACCEPT
|
iptables -A FORWARD -w -p TCP -j ACCEPT
|
||||||
iptables -A FORWARD -w -p UDP -j ACCEPT
|
iptables -A FORWARD -w -p UDP -j ACCEPT
|
||||||
iptables -A FORWARD -w -p ICMP -j ACCEPT
|
iptables -A FORWARD -w -p ICMP -j ACCEPT
|
||||||
|
iptables -A FORWARD -w -p SCTP -j ACCEPT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Flush iptables nat table
|
# Flush iptables nat table
|
||||||
|
@ -338,7 +338,7 @@ func NewProxyCommand() *cobra.Command {
|
|||||||
Use: "kube-proxy",
|
Use: "kube-proxy",
|
||||||
Long: `The Kubernetes network proxy runs on each node. This
|
Long: `The Kubernetes network proxy runs on each node. This
|
||||||
reflects services as defined in the Kubernetes API on each node and can do simple
|
reflects services as defined in the Kubernetes API on each node and can do simple
|
||||||
TCP and UDP stream forwarding or round robin TCP and UDP forwarding across a set of backends.
|
TCP, UDP, and SCTP stream forwarding or round robin TCP, UDP, and SCTP forwarding across a set of backends.
|
||||||
Service cluster IPs and ports are currently found through Docker-links-compatible
|
Service cluster IPs and ports are currently found through Docker-links-compatible
|
||||||
environment variables specifying ports opened by the service proxy. There is an optional
|
environment variables specifying ports opened by the service proxy. There is an optional
|
||||||
addon that provides cluster DNS for these cluster IPs. The user must create a service
|
addon that provides cluster DNS for these cluster IPs. The user must create a service
|
||||||
|
@ -166,6 +166,7 @@ func newProxyServer(
|
|||||||
recorder,
|
recorder,
|
||||||
healthzUpdater,
|
healthzUpdater,
|
||||||
config.NodePortAddresses,
|
config.NodePortAddresses,
|
||||||
|
config.SCTPUserSpaceNode,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||||
@ -205,6 +206,7 @@ func newProxyServer(
|
|||||||
healthzServer,
|
healthzServer,
|
||||||
config.IPVS.Scheduler,
|
config.IPVS.Scheduler,
|
||||||
config.NodePortAddresses,
|
config.NodePortAddresses,
|
||||||
|
config.SCTPUserSpaceNode,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||||
|
@ -211,6 +211,7 @@ udpIdleTimeout: 123ms
|
|||||||
nodePortAddresses:
|
nodePortAddresses:
|
||||||
- "10.20.30.40/16"
|
- "10.20.30.40/16"
|
||||||
- "fd00:1::0/64"
|
- "fd00:1::0/64"
|
||||||
|
sctpUserSpaceNode: false
|
||||||
`
|
`
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@ -325,6 +326,7 @@ nodePortAddresses:
|
|||||||
ResourceContainer: "/foo",
|
ResourceContainer: "/foo",
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
|
UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
|
||||||
NodePortAddresses: []string{"10.20.30.40/16", "fd00:1::0/64"},
|
NodePortAddresses: []string{"10.20.30.40/16", "fd00:1::0/64"},
|
||||||
|
SCTPUserSpaceNode: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
options := NewOptions()
|
options := NewOptions()
|
||||||
|
@ -61,6 +61,7 @@ ComponentConfigs:
|
|||||||
OOMScoreAdj: -999
|
OOMScoreAdj: -999
|
||||||
PortRange: ""
|
PortRange: ""
|
||||||
ResourceContainer: /kube-proxy
|
ResourceContainer: /kube-proxy
|
||||||
|
SCTPUserSpaceNode: false
|
||||||
UDPIdleTimeout: 250ms
|
UDPIdleTimeout: 250ms
|
||||||
Kubelet:
|
Kubelet:
|
||||||
Address: 1.2.3.4
|
Address: 1.2.3.4
|
||||||
|
@ -64,6 +64,7 @@ kubeProxy:
|
|||||||
oomScoreAdj: -999
|
oomScoreAdj: -999
|
||||||
portRange: ""
|
portRange: ""
|
||||||
resourceContainer: /kube-proxy
|
resourceContainer: /kube-proxy
|
||||||
|
sctpUserSpaceNode: false
|
||||||
udpIdleTimeout: 250ms
|
udpIdleTimeout: 250ms
|
||||||
kubeletConfiguration:
|
kubeletConfiguration:
|
||||||
baseConfig:
|
baseConfig:
|
||||||
|
@ -80,6 +80,7 @@ nodePortAddresses: null
|
|||||||
oomScoreAdj: -999
|
oomScoreAdj: -999
|
||||||
portRange: ""
|
portRange: ""
|
||||||
resourceContainer: /kube-proxy
|
resourceContainer: /kube-proxy
|
||||||
|
sctpUserSpaceNode: false
|
||||||
udpIdleTimeout: 250ms
|
udpIdleTimeout: 250ms
|
||||||
---
|
---
|
||||||
address: 1.2.3.4
|
address: 1.2.3.4
|
||||||
|
@ -75,6 +75,7 @@ nodePortAddresses: null
|
|||||||
oomScoreAdj: -999
|
oomScoreAdj: -999
|
||||||
portRange: ""
|
portRange: ""
|
||||||
resourceContainer: /kube-proxy
|
resourceContainer: /kube-proxy
|
||||||
|
sctpUserSpaceNode: false
|
||||||
udpIdleTimeout: 250ms
|
udpIdleTimeout: 250ms
|
||||||
---
|
---
|
||||||
address: 0.0.0.0
|
address: 0.0.0.0
|
||||||
|
2
docs/api-reference/apps/v1/definitions.html
generated
2
docs/api-reference/apps/v1/definitions.html
generated
@ -4085,7 +4085,7 @@ When an object is created, the system will populate this list with the current s
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
2
docs/api-reference/apps/v1beta1/definitions.html
generated
2
docs/api-reference/apps/v1beta1/definitions.html
generated
@ -4138,7 +4138,7 @@ The StatefulSet guarantees that a given network identity will always map to the
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
2
docs/api-reference/apps/v1beta2/definitions.html
generated
2
docs/api-reference/apps/v1beta2/definitions.html
generated
@ -4754,7 +4754,7 @@ The StatefulSet guarantees that a given network identity will always map to the
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
2
docs/api-reference/batch/v1/definitions.html
generated
2
docs/api-reference/batch/v1/definitions.html
generated
@ -3418,7 +3418,7 @@ When an object is created, the system will populate this list with the current s
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
@ -3452,7 +3452,7 @@ When an object is created, the system will populate this list with the current s
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
@ -3425,7 +3425,7 @@ When an object is created, the system will populate this list with the current s
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
@ -4784,7 +4784,7 @@ When an object is created, the system will populate this list with the current s
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
@ -8058,7 +8058,7 @@ If PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Po
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional. The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional. The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_protocol">v1.Protocol</a></p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_protocol">v1.Protocol</a></p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
@ -676,7 +676,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_protocol">v1.Protocol</a></p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_protocol">v1.Protocol</a></p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
6
docs/api-reference/v1/definitions.html
generated
6
docs/api-reference/v1/definitions.html
generated
@ -2780,7 +2780,7 @@ The resulting set of endpoints can be viewed as:<br>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP or TCP. Defaults to "TCP".</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
@ -3770,7 +3770,7 @@ Examples:<br>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The IP protocol for this port. Must be UDP or TCP. Default is TCP.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
@ -4405,7 +4405,7 @@ Examples:<br>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">protocol</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The IP protocol for this port. Supports "TCP" and "UDP". Default is TCP.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default is TCP.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
@ -263,7 +263,7 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
*d = policies[c.Rand.Intn(len(policies))]
|
*d = policies[c.Rand.Intn(len(policies))]
|
||||||
},
|
},
|
||||||
func(p *core.Protocol, c fuzz.Continue) {
|
func(p *core.Protocol, c fuzz.Continue) {
|
||||||
protocols := []core.Protocol{core.ProtocolTCP, core.ProtocolUDP}
|
protocols := []core.Protocol{core.ProtocolTCP, core.ProtocolUDP, core.ProtocolSCTP}
|
||||||
*p = protocols[c.Rand.Intn(len(protocols))]
|
*p = protocols[c.Rand.Intn(len(protocols))]
|
||||||
},
|
},
|
||||||
func(p *core.ServiceAffinity, c fuzz.Continue) {
|
func(p *core.ServiceAffinity, c fuzz.Continue) {
|
||||||
|
@ -564,6 +564,8 @@ const (
|
|||||||
ProtocolTCP Protocol = "TCP"
|
ProtocolTCP Protocol = "TCP"
|
||||||
// ProtocolUDP is the UDP protocol.
|
// ProtocolUDP is the UDP protocol.
|
||||||
ProtocolUDP Protocol = "UDP"
|
ProtocolUDP Protocol = "UDP"
|
||||||
|
// ProtocolSCTP is the SCTP protocol.
|
||||||
|
ProtocolSCTP Protocol = "SCTP"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Represents a Persistent Disk resource in Google Compute Engine.
|
// Represents a Persistent Disk resource in Google Compute Engine.
|
||||||
@ -1570,7 +1572,7 @@ type ContainerPort struct {
|
|||||||
HostPort int32
|
HostPort int32
|
||||||
// Required: This must be a valid port number, 0 < x < 65536.
|
// Required: This must be a valid port number, 0 < x < 65536.
|
||||||
ContainerPort int32
|
ContainerPort int32
|
||||||
// Required: Supports "TCP" and "UDP".
|
// Required: Supports "TCP" and "UDP". "SCTP" is supported only if no HostPort is specified.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol Protocol
|
Protocol Protocol
|
||||||
// Optional: What host IP to bind the external port to.
|
// Optional: What host IP to bind the external port to.
|
||||||
@ -3175,7 +3177,7 @@ type ServicePort struct {
|
|||||||
// the 'Name' field in EndpointPort objects.
|
// the 'Name' field in EndpointPort objects.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// The IP protocol for this port. Supports "TCP" and "UDP".
|
// The IP protocol for this port. Supports "TCP", "UDP", and SCTP.
|
||||||
Protocol Protocol
|
Protocol Protocol
|
||||||
|
|
||||||
// The port that will be exposed on the service.
|
// The port that will be exposed on the service.
|
||||||
|
@ -1918,7 +1918,10 @@ func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVo
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
var supportedPortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP))
|
var supportedServicePortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP), string(core.ProtocolSCTP))
|
||||||
|
var supportedLoadBalancerProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP))
|
||||||
|
var supportedContainerPortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP), string(core.ProtocolSCTP))
|
||||||
|
var supportedHostPortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP))
|
||||||
|
|
||||||
func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) field.ErrorList {
|
func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
@ -1951,8 +1954,12 @@ func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) fie
|
|||||||
}
|
}
|
||||||
if len(port.Protocol) == 0 {
|
if len(port.Protocol) == 0 {
|
||||||
allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
|
allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
|
||||||
} else if !supportedPortProtocols.Has(string(port.Protocol)) {
|
} else if port.HostPort != 0 {
|
||||||
allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
|
if !supportedHostPortProtocols.Has(string(port.Protocol)) {
|
||||||
|
allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedHostPortProtocols.List()))
|
||||||
|
}
|
||||||
|
} else if !supportedContainerPortProtocols.Has(string(port.Protocol)) {
|
||||||
|
allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedContainerPortProtocols.List()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -3726,7 +3733,7 @@ func ValidateService(service *core.Service) field.ErrorList {
|
|||||||
includeProtocols := sets.NewString()
|
includeProtocols := sets.NewString()
|
||||||
for i := range service.Spec.Ports {
|
for i := range service.Spec.Ports {
|
||||||
portPath := portsPath.Index(i)
|
portPath := portsPath.Index(i)
|
||||||
if !supportedPortProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
|
if !supportedLoadBalancerProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
|
||||||
allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP ports"))
|
allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP ports"))
|
||||||
} else {
|
} else {
|
||||||
includeProtocols.Insert(string(service.Spec.Ports[i].Protocol))
|
includeProtocols.Insert(string(service.Spec.Ports[i].Protocol))
|
||||||
@ -3825,8 +3832,8 @@ func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bo
|
|||||||
|
|
||||||
if len(sp.Protocol) == 0 {
|
if len(sp.Protocol) == 0 {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
|
allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
|
||||||
} else if !supportedPortProtocols.Has(string(sp.Protocol)) {
|
} else if !supportedServicePortProtocols.Has(string(sp.Protocol)) {
|
||||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List()))
|
allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedServicePortProtocols.List()))
|
||||||
}
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...)
|
allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...)
|
||||||
@ -5194,8 +5201,8 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
|
|||||||
}
|
}
|
||||||
if len(port.Protocol) == 0 {
|
if len(port.Protocol) == 0 {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
|
allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
|
||||||
} else if !supportedPortProtocols.Has(string(port.Protocol)) {
|
} else if !supportedServicePortProtocols.Has(string(port.Protocol)) {
|
||||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
|
allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedServicePortProtocols.List()))
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
@ -4125,12 +4125,12 @@ func TestValidatePorts(t *testing.T) {
|
|||||||
"invalid protocol case": {
|
"invalid protocol case": {
|
||||||
[]core.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}},
|
[]core.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}},
|
||||||
field.ErrorTypeNotSupported,
|
field.ErrorTypeNotSupported,
|
||||||
"protocol", `supported values: "TCP", "UDP"`,
|
"protocol", `supported values: "SCTP", "TCP", "UDP"`,
|
||||||
},
|
},
|
||||||
"invalid protocol": {
|
"invalid protocol": {
|
||||||
[]core.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}},
|
[]core.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}},
|
||||||
field.ErrorTypeNotSupported,
|
field.ErrorTypeNotSupported,
|
||||||
"protocol", `supported values: "TCP", "UDP"`,
|
"protocol", `supported values: "SCTP", "TCP", "UDP"`,
|
||||||
},
|
},
|
||||||
"protocol required": {
|
"protocol required": {
|
||||||
[]core.ContainerPort{{Name: "abc", ContainerPort: 80}},
|
[]core.ContainerPort{{Name: "abc", ContainerPort: 80}},
|
||||||
@ -8947,6 +8947,7 @@ func TestValidateService(t *testing.T) {
|
|||||||
s.Spec.Type = core.ServiceTypeNodePort
|
s.Spec.Type = core.ServiceTypeNodePort
|
||||||
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", NodePort: 1, TargetPort: intstr.FromInt(1)})
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", NodePort: 1, TargetPort: intstr.FromInt(1)})
|
||||||
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "UDP", NodePort: 1, TargetPort: intstr.FromInt(2)})
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "UDP", NodePort: 1, TargetPort: intstr.FromInt(2)})
|
||||||
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "s", Port: 3, Protocol: "SCTP", NodePort: 1, TargetPort: intstr.FromInt(3)})
|
||||||
},
|
},
|
||||||
numErrs: 0,
|
numErrs: 0,
|
||||||
},
|
},
|
||||||
@ -8965,6 +8966,7 @@ func TestValidateService(t *testing.T) {
|
|||||||
s.Spec.Type = core.ServiceTypeClusterIP
|
s.Spec.Type = core.ServiceTypeClusterIP
|
||||||
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 12345, Protocol: "TCP", TargetPort: intstr.FromInt(8080)})
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 12345, Protocol: "TCP", TargetPort: intstr.FromInt(8080)})
|
||||||
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 12345, Protocol: "UDP", TargetPort: intstr.FromInt(80)})
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 12345, Protocol: "UDP", TargetPort: intstr.FromInt(80)})
|
||||||
|
s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "s", Port: 12345, Protocol: "SCTP", TargetPort: intstr.FromInt(8088)})
|
||||||
},
|
},
|
||||||
numErrs: 0,
|
numErrs: 0,
|
||||||
},
|
},
|
||||||
|
@ -134,7 +134,7 @@ type NetworkPolicyEgressRule struct {
|
|||||||
|
|
||||||
// NetworkPolicyPort describes a port to allow traffic on
|
// NetworkPolicyPort describes a port to allow traffic on
|
||||||
type NetworkPolicyPort struct {
|
type NetworkPolicyPort struct {
|
||||||
// The protocol (TCP or UDP) which traffic must match. If not specified, this
|
// The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this
|
||||||
// field defaults to TCP.
|
// field defaults to TCP.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol *api.Protocol
|
Protocol *api.Protocol
|
||||||
|
@ -38,8 +38,8 @@ func ValidateNetworkPolicyName(name string, prefix bool) []string {
|
|||||||
func ValidateNetworkPolicyPort(port *networking.NetworkPolicyPort, portPath *field.Path) field.ErrorList {
|
func ValidateNetworkPolicyPort(port *networking.NetworkPolicyPort, portPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
if port.Protocol != nil && *port.Protocol != api.ProtocolTCP && *port.Protocol != api.ProtocolUDP {
|
if port.Protocol != nil && *port.Protocol != api.ProtocolTCP && *port.Protocol != api.ProtocolUDP && *port.Protocol != api.ProtocolSCTP {
|
||||||
allErrs = append(allErrs, field.NotSupported(portPath.Child("protocol"), *port.Protocol, []string{string(api.ProtocolTCP), string(api.ProtocolUDP)}))
|
allErrs = append(allErrs, field.NotSupported(portPath.Child("protocol"), *port.Protocol, []string{string(api.ProtocolTCP), string(api.ProtocolUDP), string(api.ProtocolSCTP)}))
|
||||||
}
|
}
|
||||||
if port.Port != nil {
|
if port.Port != nil {
|
||||||
if port.Port.Type == intstr.Int {
|
if port.Port.Type == intstr.Int {
|
||||||
|
@ -29,6 +29,7 @@ func TestValidateNetworkPolicy(t *testing.T) {
|
|||||||
protocolTCP := api.ProtocolTCP
|
protocolTCP := api.ProtocolTCP
|
||||||
protocolUDP := api.ProtocolUDP
|
protocolUDP := api.ProtocolUDP
|
||||||
protocolICMP := api.Protocol("ICMP")
|
protocolICMP := api.Protocol("ICMP")
|
||||||
|
protocolSCTP := api.ProtocolSCTP
|
||||||
|
|
||||||
successCases := []networking.NetworkPolicy{
|
successCases := []networking.NetworkPolicy{
|
||||||
{
|
{
|
||||||
@ -79,6 +80,10 @@ func TestValidateNetworkPolicy(t *testing.T) {
|
|||||||
Protocol: &protocolUDP,
|
Protocol: &protocolUDP,
|
||||||
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
|
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Protocol: &protocolSCTP,
|
||||||
|
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 7777},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -262,6 +267,10 @@ func TestValidateNetworkPolicy(t *testing.T) {
|
|||||||
Protocol: &protocolUDP,
|
Protocol: &protocolUDP,
|
||||||
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
|
Port: &intstr.IntOrString{Type: intstr.String, StrVal: "dns"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Protocol: &protocolSCTP,
|
||||||
|
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 7777},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -737,6 +737,13 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service,
|
|||||||
return nil, fmt.Errorf("services requiring health checks are incompatible with UDP ports")
|
return nil, fmt.Errorf("services requiring health checks are incompatible with UDP ports")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if port.Protocol == v1.ProtocolSCTP {
|
||||||
|
// ERROR: this isn't supported
|
||||||
|
// health check (aka source ip preservation) is not
|
||||||
|
// compatible with SCTP (it uses an HTTP check)
|
||||||
|
return nil, fmt.Errorf("services requiring health checks are incompatible with SCTP ports")
|
||||||
|
}
|
||||||
|
|
||||||
podPresencePath, podPresencePort := serviceapi.GetServiceHealthCheckPathPort(service)
|
podPresencePath, podPresencePort := serviceapi.GetServiceHealthCheckPathPort(service)
|
||||||
|
|
||||||
expectedProbes = append(expectedProbes, network.Probe{
|
expectedProbes = append(expectedProbes, network.Probe{
|
||||||
@ -749,7 +756,7 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service,
|
|||||||
NumberOfProbes: to.Int32Ptr(2),
|
NumberOfProbes: to.Int32Ptr(2),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if port.Protocol != v1.ProtocolUDP {
|
} else if port.Protocol != v1.ProtocolUDP && port.Protocol != v1.ProtocolSCTP {
|
||||||
// we only add the expected probe if we're doing TCP
|
// we only add the expected probe if we're doing TCP
|
||||||
expectedProbes = append(expectedProbes, network.Probe{
|
expectedProbes = append(expectedProbes, network.Probe{
|
||||||
Name: &lbRuleName,
|
Name: &lbRuleName,
|
||||||
@ -787,8 +794,8 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service,
|
|||||||
expectedRule.LoadBalancingRulePropertiesFormat.IdleTimeoutInMinutes = lbIdleTimeout
|
expectedRule.LoadBalancingRulePropertiesFormat.IdleTimeoutInMinutes = lbIdleTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// we didn't construct the probe objects for UDP because they're not used/needed/allowed
|
// we didn't construct the probe objects for UDP or SCTP because they're not used/needed/allowed
|
||||||
if port.Protocol != v1.ProtocolUDP {
|
if port.Protocol != v1.ProtocolUDP && port.Protocol != v1.ProtocolSCTP {
|
||||||
expectedRule.Probe = &network.SubResource{
|
expectedRule.Probe = &network.SubResource{
|
||||||
ID: to.StringPtr(az.getLoadBalancerProbeID(lbName, lbRuleName)),
|
ID: to.StringPtr(az.getLoadBalancerProbeID(lbName, lbRuleName)),
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,9 @@ const (
|
|||||||
func (gce *GCECloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v1.Service, existingFwdRule *compute.ForwardingRule, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) {
|
func (gce *GCECloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v1.Service, existingFwdRule *compute.ForwardingRule, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) {
|
||||||
nm := types.NamespacedName{Name: svc.Name, Namespace: svc.Namespace}
|
nm := types.NamespacedName{Name: svc.Name, Namespace: svc.Namespace}
|
||||||
ports, protocol := getPortsAndProtocol(svc.Spec.Ports)
|
ports, protocol := getPortsAndProtocol(svc.Spec.Ports)
|
||||||
|
if protocol != v1.ProtocolTCP && protocol != v1.ProtocolUDP {
|
||||||
|
return nil, fmt.Errorf("Invalid protocol %s, only TCP and UDP are supported", string(protocol))
|
||||||
|
}
|
||||||
scheme := cloud.SchemeInternal
|
scheme := cloud.SchemeInternal
|
||||||
loadBalancerName := gce.GetLoadBalancerName(context.TODO(), clusterName, svc)
|
loadBalancerName := gce.GetLoadBalancerName(context.TODO(), clusterName, svc)
|
||||||
sharedBackend := shareBackendService(svc)
|
sharedBackend := shareBackendService(svc)
|
||||||
|
@ -103,11 +103,15 @@ func TestFirewallToGcloudArgs(t *testing.T) {
|
|||||||
IPProtocol: "tcp",
|
IPProtocol: "tcp",
|
||||||
Ports: []string{"321", "123-456", "123"},
|
Ports: []string{"321", "123-456", "123"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
IPProtocol: "sctp",
|
||||||
|
Ports: []string{"321", "123-456", "123"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
got := firewallToGcloudArgs(&firewall, "my-project")
|
got := firewallToGcloudArgs(&firewall, "my-project")
|
||||||
|
|
||||||
var e = `--description "Last Line of Defense" --allow tcp:123,tcp:123-456,tcp:321,udp:123,udp:123-456,udp:321 --source-ranges 1.1.1.1/20,2.2.2.2/20,3.3.3.3/20 --target-tags band-nodes,jock-nodes --project my-project`
|
var e = `--description "Last Line of Defense" --allow sctp:123,sctp:123-456,sctp:321,tcp:123,tcp:123-456,tcp:321,udp:123,udp:123-456,udp:321 --source-ranges 1.1.1.1/20,2.2.2.2/20,3.3.3.3/20 --target-tags band-nodes,jock-nodes --project my-project`
|
||||||
if got != e {
|
if got != e {
|
||||||
t.Errorf("%q does not equal %q", got, e)
|
t.Errorf("%q does not equal %q", got, e)
|
||||||
}
|
}
|
||||||
|
@ -344,6 +344,47 @@ func TestSyncEndpointsProtocolUDP(t *testing.T) {
|
|||||||
endpointsHandler.ValidateRequest(t, testapi.Default.ResourcePath("endpoints", ns, "foo"), "PUT", &data)
|
endpointsHandler.ValidateRequest(t, testapi.Default.ResourcePath("endpoints", ns, "foo"), "PUT", &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSyncEndpointsProtocolSCTP(t *testing.T) {
|
||||||
|
ns := "other"
|
||||||
|
testServer, endpointsHandler := makeTestServer(t, ns)
|
||||||
|
defer testServer.Close()
|
||||||
|
endpoints := newController(testServer.URL)
|
||||||
|
endpoints.endpointsStore.Add(&v1.Endpoints{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
Subsets: []v1.EndpointSubset{{
|
||||||
|
Addresses: []v1.EndpointAddress{{IP: "6.7.8.9", NodeName: &emptyNodeName}},
|
||||||
|
Ports: []v1.EndpointPort{{Port: 1000, Protocol: "SCTP"}},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
addPods(endpoints.podStore, ns, 1, 1, 0)
|
||||||
|
endpoints.serviceStore.Add(&v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{},
|
||||||
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "SCTP"}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
endpoints.syncService(ns + "/foo")
|
||||||
|
|
||||||
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
|
data := runtime.EncodeOrDie(testapi.Default.Codec(), &v1.Endpoints{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
Subsets: []v1.EndpointSubset{{
|
||||||
|
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", NodeName: &emptyNodeName, TargetRef: &v1.ObjectReference{Kind: "Pod", Name: "pod0", Namespace: ns}}},
|
||||||
|
Ports: []v1.EndpointPort{{Port: 8080, Protocol: "SCTP"}},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
endpointsHandler.ValidateRequest(t, testapi.Default.ResourcePath("endpoints", ns, "foo"), "PUT", &data)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSyncEndpointsItemsEmptySelectorSelectsAll(t *testing.T) {
|
func TestSyncEndpointsItemsEmptySelectorSelectsAll(t *testing.T) {
|
||||||
ns := "other"
|
ns := "other"
|
||||||
testServer, endpointsHandler := makeTestServer(t, ns)
|
testServer, endpointsHandler := makeTestServer(t, ns)
|
||||||
|
@ -124,6 +124,24 @@ func TestCreateExternalLoadBalancer(t *testing.T) {
|
|||||||
expectErr: false,
|
expectErr: false,
|
||||||
expectCreateAttempt: true,
|
expectCreateAttempt: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
service: &v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sctp-service",
|
||||||
|
Namespace: "default",
|
||||||
|
SelfLink: testapi.Default.SelfLink("services", "sctp-service"),
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Ports: []v1.ServicePort{{
|
||||||
|
Port: 80,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
}},
|
||||||
|
Type: v1.ServiceTypeLoadBalancer,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expectCreateAttempt: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
|
@ -126,7 +126,7 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]",
|
Use: "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]",
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Short: i18n.T("Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service"),
|
Short: i18n.T("Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service"),
|
||||||
Long: exposeLong,
|
Long: exposeLong,
|
||||||
|
@ -425,6 +425,11 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Port: 8081,
|
Port: 8081,
|
||||||
TargetPort: intstr.FromInt(8081),
|
TargetPort: intstr.FromInt(8081),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 8082,
|
||||||
|
TargetPort: intstr.FromInt(8082),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -451,12 +456,144 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Port: 8081,
|
Port: 8081,
|
||||||
TargetPort: intstr.FromInt(8081),
|
TargetPort: intstr.FromInt(8081),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "port-4",
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 8082,
|
||||||
|
TargetPort: intstr.FromInt(8082),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Selector: map[string]string{"svc": "fromfoo"},
|
Selector: map[string]string{"svc": "fromfoo"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "expose-service-from-service-no-selector-defined-sctp",
|
||||||
|
args: []string{"service", "baz"},
|
||||||
|
ns: "test",
|
||||||
|
calls: map[string]string{
|
||||||
|
"GET": "/namespaces/test/services/baz",
|
||||||
|
"POST": "/namespaces/test/services",
|
||||||
|
},
|
||||||
|
input: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Selector: map[string]string{"app": "go"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
flags: map[string]string{"protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test"},
|
||||||
|
output: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 14,
|
||||||
|
TargetPort: intstr.FromInt(14),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: map[string]string{"app": "go"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "service/foo exposed",
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expose-service-from-service-sctp",
|
||||||
|
args: []string{"service", "baz"},
|
||||||
|
ns: "test",
|
||||||
|
calls: map[string]string{
|
||||||
|
"GET": "/namespaces/test/services/baz",
|
||||||
|
"POST": "/namespaces/test/services",
|
||||||
|
},
|
||||||
|
input: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Selector: map[string]string{"app": "go"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test"},
|
||||||
|
output: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 14,
|
||||||
|
TargetPort: intstr.FromInt(14),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: map[string]string{"func": "stream"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "service/foo exposed",
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expose-service-cluster-ip-sctp",
|
||||||
|
args: []string{"service", "baz"},
|
||||||
|
ns: "test",
|
||||||
|
calls: map[string]string{
|
||||||
|
"GET": "/namespaces/test/services/baz",
|
||||||
|
"POST": "/namespaces/test/services",
|
||||||
|
},
|
||||||
|
input: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Selector: map[string]string{"app": "go"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "10.10.10.10", "dry-run": "true"},
|
||||||
|
output: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 14,
|
||||||
|
TargetPort: intstr.FromInt(14),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: map[string]string{"func": "stream"},
|
||||||
|
ClusterIP: "10.10.10.10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "service /foo exposed",
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expose-headless-service-sctp",
|
||||||
|
args: []string{"service", "baz"},
|
||||||
|
ns: "test",
|
||||||
|
calls: map[string]string{
|
||||||
|
"GET": "/namespaces/test/services/baz",
|
||||||
|
"POST": "/namespaces/test/services",
|
||||||
|
},
|
||||||
|
input: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Selector: map[string]string{"app": "go"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "None", "dry-run": "true"},
|
||||||
|
output: &corev1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Protocol: corev1.ProtocolSCTP,
|
||||||
|
Port: 14,
|
||||||
|
TargetPort: intstr.FromInt(14),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: map[string]string{"func": "stream"},
|
||||||
|
ClusterIP: corev1.ClusterIPNone,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "service/foo exposed",
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"status": "Failure",
|
"status": "Failure",
|
||||||
"message": "Service \"svc2\" is invalid: [spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP, spec.clusterIP: Invalid value: \"10.0.0.182.1\": must be empty, 'None', or a valid IP address]",
|
"message": "Service \"svc2\" is invalid: [spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP, spec.clusterIP: Invalid value: \"10.0.0.182.1\": must be empty, 'None', or a valid IP address]",
|
||||||
"reason": "Invalid",
|
"reason": "Invalid",
|
||||||
"details": {
|
"details": {
|
||||||
"name": "svc2",
|
"name": "svc2",
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"causes": [
|
"causes": [
|
||||||
{
|
{
|
||||||
"reason": "FieldValueNotSupported",
|
"reason": "FieldValueNotSupported",
|
||||||
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP",
|
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP",
|
||||||
"field": "spec.ports[0].protocol"
|
"field": "spec.ports[0].protocol"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"status": "Failure",
|
"status": "Failure",
|
||||||
"message": "Service \"svc1\" is invalid: [spec.clusterIP: Invalid value: \"10.0.0.10\": field is immutable, spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP]",
|
"message": "Service \"svc1\" is invalid: [spec.clusterIP: Invalid value: \"10.0.0.10\": field is immutable, spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP]",
|
||||||
"reason": "Invalid",
|
"reason": "Invalid",
|
||||||
"details": {
|
"details": {
|
||||||
"name": "svc1",
|
"name": "svc1",
|
||||||
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"reason": "FieldValueNotSupported",
|
"reason": "FieldValueNotSupported",
|
||||||
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP",
|
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP",
|
||||||
"field": "spec.ports[0].protocol"
|
"field": "spec.ports[0].protocol"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# services "svc1" was not valid:
|
# services "svc1" was not valid:
|
||||||
# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable
|
# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable
|
||||||
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP
|
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP, SCTP
|
||||||
#
|
#
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
items:
|
items:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# services "svc1" was not valid:
|
# services "svc1" was not valid:
|
||||||
# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable
|
# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable
|
||||||
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP
|
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP, SCTP
|
||||||
#
|
#
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
items:
|
items:
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"status": "Failure",
|
"status": "Failure",
|
||||||
"message": "Service \"svc1\" is invalid: spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP",
|
"message": "Service \"svc1\" is invalid: spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP",
|
||||||
"reason": "Invalid",
|
"reason": "Invalid",
|
||||||
"details": {
|
"details": {
|
||||||
"name": "svc1",
|
"name": "svc1",
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"causes": [
|
"causes": [
|
||||||
{
|
{
|
||||||
"reason": "FieldValueNotSupported",
|
"reason": "FieldValueNotSupported",
|
||||||
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP",
|
"message": "Unsupported value: \"VHF\": supported values: TCP, UDP, SCTP",
|
||||||
"field": "spec.ports[0].protocol"
|
"field": "spec.ports[0].protocol"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# reopened with the relevant failures.
|
# reopened with the relevant failures.
|
||||||
#
|
#
|
||||||
# services "svc1" was not valid:
|
# services "svc1" was not valid:
|
||||||
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP
|
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP, SCTP
|
||||||
#
|
#
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
items:
|
items:
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# reopened with the relevant failures.
|
# reopened with the relevant failures.
|
||||||
#
|
#
|
||||||
# services "svc1" was not valid:
|
# services "svc1" was not valid:
|
||||||
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP
|
# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP, SCTP
|
||||||
#
|
#
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
items:
|
items:
|
||||||
|
@ -366,10 +366,12 @@ func TestMakeParseProtocols(t *testing.T) {
|
|||||||
protocols: map[string]string{
|
protocols: map[string]string{
|
||||||
"102": "UDP",
|
"102": "UDP",
|
||||||
"101": "TCP",
|
"101": "TCP",
|
||||||
|
"103": "SCTP",
|
||||||
},
|
},
|
||||||
expected: map[string]string{
|
expected: map[string]string{
|
||||||
"102": "UDP",
|
"102": "UDP",
|
||||||
"101": "TCP",
|
"101": "TCP",
|
||||||
|
"103": "SCTP",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -598,6 +598,355 @@ func TestGenerateService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"labels": "key1=value1,key2=value2",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV1{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "default",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV1{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
"session-affinity": "ClientIP",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "default",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SessionAffinity: v1.ServiceAffinityClientIP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
"cluster-ip": "10.10.10.10",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ClusterIP: "10.10.10.10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"port": "80",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
"cluster-ip": "None",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
TargetPort: intstr.FromInt(1234),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ClusterIP: v1.ClusterIPNone,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV1{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar",
|
||||||
|
"name": "test",
|
||||||
|
"ports": "80,443",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "foobar",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "port-1",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromString("foobar"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-2",
|
||||||
|
Port: 443,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromString("foobar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar",
|
||||||
|
"name": "test",
|
||||||
|
"ports": "80,443",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "port-1",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-2",
|
||||||
|
Port: 443,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromInt(443),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar",
|
||||||
|
"name": "test",
|
||||||
|
"ports": "80,8080",
|
||||||
|
"protocols": "8080/SCTP",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "port-1",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
TargetPort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-2",
|
||||||
|
Port: 8080,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromInt(8080),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar",
|
||||||
|
"name": "test",
|
||||||
|
"ports": "80,8080,8081,8082",
|
||||||
|
"protocols": "8080/UDP,8081/TCP,8082/SCTP",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "port-1",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
TargetPort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-2",
|
||||||
|
Port: 8080,
|
||||||
|
Protocol: v1.ProtocolUDP,
|
||||||
|
TargetPort: intstr.FromInt(8080),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-3",
|
||||||
|
Port: 8081,
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
TargetPort: intstr.FromInt(8081),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "port-4",
|
||||||
|
Port: 8082,
|
||||||
|
Protocol: v1.ProtocolSCTP,
|
||||||
|
TargetPort: intstr.FromInt(8082),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
generator: ServiceGeneratorV2{},
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"selector": "foo=bar,baz=blah",
|
||||||
|
"name": "test",
|
||||||
|
"protocol": "SCTP",
|
||||||
|
"container-port": "1234",
|
||||||
|
"cluster-ip": "None",
|
||||||
|
},
|
||||||
|
expected: v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "blah",
|
||||||
|
},
|
||||||
|
Ports: []v1.ServicePort{},
|
||||||
|
ClusterIP: v1.ClusterIPNone,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -162,15 +162,18 @@ type Protocol int32
|
|||||||
const (
|
const (
|
||||||
Protocol_TCP Protocol = 0
|
Protocol_TCP Protocol = 0
|
||||||
Protocol_UDP Protocol = 1
|
Protocol_UDP Protocol = 1
|
||||||
|
Protocol_SCTP Protocol = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var Protocol_name = map[int32]string{
|
var Protocol_name = map[int32]string{
|
||||||
0: "TCP",
|
0: "TCP",
|
||||||
1: "UDP",
|
1: "UDP",
|
||||||
|
2: "SCTP",
|
||||||
}
|
}
|
||||||
var Protocol_value = map[string]int32{
|
var Protocol_value = map[string]int32{
|
||||||
"TCP": 0,
|
"TCP": 0,
|
||||||
"UDP": 1,
|
"UDP": 1,
|
||||||
|
"SCTP": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Protocol) String() string {
|
func (x Protocol) String() string {
|
||||||
|
@ -143,6 +143,7 @@ message DNSConfig {
|
|||||||
enum Protocol {
|
enum Protocol {
|
||||||
TCP = 0;
|
TCP = 0;
|
||||||
UDP = 1;
|
UDP = 1;
|
||||||
|
SCTP = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortMapping specifies the port mapping configurations of a sandbox.
|
// PortMapping specifies the port mapping configurations of a sandbox.
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
sandboxCheckpointDir = "sandbox"
|
sandboxCheckpointDir = "sandbox"
|
||||||
protocolTCP = Protocol("tcp")
|
protocolTCP = Protocol("tcp")
|
||||||
protocolUDP = Protocol("udp")
|
protocolUDP = Protocol("udp")
|
||||||
|
protocolSCTP = Protocol("sctp")
|
||||||
schemaVersion = "v1"
|
schemaVersion = "v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -672,6 +672,8 @@ func toCheckpointProtocol(protocol runtimeapi.Protocol) Protocol {
|
|||||||
return protocolTCP
|
return protocolTCP
|
||||||
case runtimeapi.Protocol_UDP:
|
case runtimeapi.Protocol_UDP:
|
||||||
return protocolUDP
|
return protocolUDP
|
||||||
|
case runtimeapi.Protocol_SCTP:
|
||||||
|
return protocolSCTP
|
||||||
}
|
}
|
||||||
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
||||||
return protocolTCP
|
return protocolTCP
|
||||||
|
@ -515,6 +515,8 @@ func toAPIProtocol(protocol Protocol) v1.Protocol {
|
|||||||
return v1.ProtocolTCP
|
return v1.ProtocolTCP
|
||||||
case protocolUDP:
|
case protocolUDP:
|
||||||
return v1.ProtocolUDP
|
return v1.ProtocolUDP
|
||||||
|
case protocolSCTP:
|
||||||
|
return v1.ProtocolSCTP
|
||||||
}
|
}
|
||||||
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
||||||
return v1.ProtocolTCP
|
return v1.ProtocolTCP
|
||||||
|
@ -172,6 +172,8 @@ func makePortsAndBindings(pm []*runtimeapi.PortMapping) (dockernat.PortSet, map[
|
|||||||
protocol = "/udp"
|
protocol = "/udp"
|
||||||
case runtimeapi.Protocol_TCP:
|
case runtimeapi.Protocol_TCP:
|
||||||
protocol = "/tcp"
|
protocol = "/tcp"
|
||||||
|
case runtimeapi.Protocol_SCTP:
|
||||||
|
protocol = "/sctp"
|
||||||
default:
|
default:
|
||||||
glog.Warningf("Unknown protocol %q: defaulting to TCP", port.Protocol)
|
glog.Warningf("Unknown protocol %q: defaulting to TCP", port.Protocol)
|
||||||
protocol = "/tcp"
|
protocol = "/tcp"
|
||||||
|
@ -83,6 +83,16 @@ func TestOpenCloseHostports(t *testing.T) {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&PodPortMapping{
|
||||||
|
Namespace: "ns1",
|
||||||
|
Name: "n4",
|
||||||
|
PortMappings: []*PortMapping{
|
||||||
|
{HostPort: 7777, Protocol: v1.Protocol("STCP")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
iptables := NewFakeIPTables()
|
iptables := NewFakeIPTables()
|
||||||
@ -269,9 +279,11 @@ func TestHostportManager(t *testing.T) {
|
|||||||
`:KUBE-HP-IJHALPHTORMHHPPK - [0:0]`: true,
|
`:KUBE-HP-IJHALPHTORMHHPPK - [0:0]`: true,
|
||||||
`:KUBE-HP-63UPIDJXVRSZGSUZ - [0:0]`: true,
|
`:KUBE-HP-63UPIDJXVRSZGSUZ - [0:0]`: true,
|
||||||
`:KUBE-HP-WFBOALXEP42XEMJK - [0:0]`: true,
|
`:KUBE-HP-WFBOALXEP42XEMJK - [0:0]`: true,
|
||||||
|
`:KUBE-HP-XU6AWMMJYOZOFTFZ - [0:0]`: true,
|
||||||
"-A KUBE-HOSTPORTS -m comment --comment \"pod3_ns1 hostport 8443\" -m tcp -p tcp --dport 8443 -j KUBE-HP-WFBOALXEP42XEMJK": true,
|
"-A KUBE-HOSTPORTS -m comment --comment \"pod3_ns1 hostport 8443\" -m tcp -p tcp --dport 8443 -j KUBE-HP-WFBOALXEP42XEMJK": true,
|
||||||
"-A KUBE-HOSTPORTS -m comment --comment \"pod1_ns1 hostport 8081\" -m udp -p udp --dport 8081 -j KUBE-HP-63UPIDJXVRSZGSUZ": true,
|
"-A KUBE-HOSTPORTS -m comment --comment \"pod1_ns1 hostport 8081\" -m udp -p udp --dport 8081 -j KUBE-HP-63UPIDJXVRSZGSUZ": true,
|
||||||
"-A KUBE-HOSTPORTS -m comment --comment \"pod1_ns1 hostport 8080\" -m tcp -p tcp --dport 8080 -j KUBE-HP-IJHALPHTORMHHPPK": true,
|
"-A KUBE-HOSTPORTS -m comment --comment \"pod1_ns1 hostport 8080\" -m tcp -p tcp --dport 8080 -j KUBE-HP-IJHALPHTORMHHPPK": true,
|
||||||
|
"-A KUBE-HOSTPORTS -m comment --comment \"pod1_ns1 hostport 8083\" -m sctp -p sctp --dport 8083 -j KUBE-HP-XU6AWMMJYOZOFTFZ": true,
|
||||||
"-A OUTPUT -m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS": true,
|
"-A OUTPUT -m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS": true,
|
||||||
"-A PREROUTING -m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS": true,
|
"-A PREROUTING -m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS": true,
|
||||||
"-A POSTROUTING -m comment --comment \"SNAT for localhost access to hostports\" -o cbr0 -s 127.0.0.0/8 -j MASQUERADE": true,
|
"-A POSTROUTING -m comment --comment \"SNAT for localhost access to hostports\" -o cbr0 -s 127.0.0.0/8 -j MASQUERADE": true,
|
||||||
@ -279,6 +291,8 @@ func TestHostportManager(t *testing.T) {
|
|||||||
"-A KUBE-HP-IJHALPHTORMHHPPK -m comment --comment \"pod1_ns1 hostport 8080\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.2:80": true,
|
"-A KUBE-HP-IJHALPHTORMHHPPK -m comment --comment \"pod1_ns1 hostport 8080\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.2:80": true,
|
||||||
"-A KUBE-HP-63UPIDJXVRSZGSUZ -m comment --comment \"pod1_ns1 hostport 8081\" -s 10.1.1.2/32 -j KUBE-MARK-MASQ": true,
|
"-A KUBE-HP-63UPIDJXVRSZGSUZ -m comment --comment \"pod1_ns1 hostport 8081\" -s 10.1.1.2/32 -j KUBE-MARK-MASQ": true,
|
||||||
"-A KUBE-HP-63UPIDJXVRSZGSUZ -m comment --comment \"pod1_ns1 hostport 8081\" -m udp -p udp -j DNAT --to-destination 10.1.1.2:81": true,
|
"-A KUBE-HP-63UPIDJXVRSZGSUZ -m comment --comment \"pod1_ns1 hostport 8081\" -m udp -p udp -j DNAT --to-destination 10.1.1.2:81": true,
|
||||||
|
"-A KUBE-HP-XU6AWMMJYOZOFTFZ -m comment --comment \"pod1_ns1 hostport 8083\" -s 10.1.1.2/32 -j KUBE-MARK-MASQ": true,
|
||||||
|
"-A KUBE-HP-XU6AWMMJYOZOFTFZ -m comment --comment \"pod1_ns1 hostport 8083\" -m sctp -p sctp -j DNAT --to-destination 10.1.1.2:83": true,
|
||||||
"-A KUBE-HP-WFBOALXEP42XEMJK -m comment --comment \"pod3_ns1 hostport 8443\" -s 10.1.1.4/32 -j KUBE-MARK-MASQ": true,
|
"-A KUBE-HP-WFBOALXEP42XEMJK -m comment --comment \"pod3_ns1 hostport 8443\" -s 10.1.1.4/32 -j KUBE-MARK-MASQ": true,
|
||||||
"-A KUBE-HP-WFBOALXEP42XEMJK -m comment --comment \"pod3_ns1 hostport 8443\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.4:443": true,
|
"-A KUBE-HP-WFBOALXEP42XEMJK -m comment --comment \"pod3_ns1 hostport 8443\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.4:443": true,
|
||||||
`COMMIT`: true,
|
`COMMIT`: true,
|
||||||
|
@ -90,6 +90,16 @@ func TestFromServices(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "sctp-1"},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: map[string]string{"bar": "sctp-sel"},
|
||||||
|
ClusterIP: "1.2.3.4",
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{Port: 777, Protocol: "SCTP"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
vars := envvars.FromServices(sl)
|
vars := envvars.FromServices(sl)
|
||||||
expected := []v1.EnvVar{
|
expected := []v1.EnvVar{
|
||||||
@ -138,6 +148,13 @@ func TestFromServices(t *testing.T) {
|
|||||||
{Name: "SUPER_IPV6_PORT_8084_TCP_PROTO", Value: "tcp"},
|
{Name: "SUPER_IPV6_PORT_8084_TCP_PROTO", Value: "tcp"},
|
||||||
{Name: "SUPER_IPV6_PORT_8084_TCP_PORT", Value: "8084"},
|
{Name: "SUPER_IPV6_PORT_8084_TCP_PORT", Value: "8084"},
|
||||||
{Name: "SUPER_IPV6_PORT_8084_TCP_ADDR", Value: "2001:DB8::"},
|
{Name: "SUPER_IPV6_PORT_8084_TCP_ADDR", Value: "2001:DB8::"},
|
||||||
|
{Name: "SCTP_1_SERVICE_HOST", Value: "1.2.3.4"},
|
||||||
|
{Name: "SCTP_1_SERVICE_PORT", Value: "777"},
|
||||||
|
{Name: "SCTP_1_PORT", Value: "sctp://1.2.3.4:777"},
|
||||||
|
{Name: "SCTP_1_PORT_777_SCTP", Value: "sctp://1.2.3.4:777"},
|
||||||
|
{Name: "SCTP_1_PORT_777_SCTP_PROTO", Value: "sctp"},
|
||||||
|
{Name: "SCTP_1_PORT_777_SCTP_PORT", Value: "777"},
|
||||||
|
{Name: "SCTP_1_PORT_777_SCTP_ADDR", Value: "1.2.3.4"},
|
||||||
}
|
}
|
||||||
if len(vars) != len(expected) {
|
if len(vars) != len(expected) {
|
||||||
t.Errorf("Expected %d env vars, got: %+v", len(expected), vars)
|
t.Errorf("Expected %d env vars, got: %+v", len(expected), vars)
|
||||||
|
@ -79,6 +79,8 @@ func toRuntimeProtocol(protocol v1.Protocol) runtimeapi.Protocol {
|
|||||||
return runtimeapi.Protocol_TCP
|
return runtimeapi.Protocol_TCP
|
||||||
case v1.ProtocolUDP:
|
case v1.ProtocolUDP:
|
||||||
return runtimeapi.Protocol_UDP
|
return runtimeapi.Protocol_UDP
|
||||||
|
case v1.ProtocolSCTP:
|
||||||
|
return runtimeapi.Protocol_SCTP
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol)
|
||||||
|
@ -94,6 +94,7 @@ func NewHollowProxyOrDie(
|
|||||||
recorder,
|
recorder,
|
||||||
nil,
|
nil,
|
||||||
[]string{},
|
[]string{},
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||||
|
@ -372,6 +372,20 @@ func TestReconcileEndpoints(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testName: "no existing sctp endpoints",
|
||||||
|
serviceName: "boo",
|
||||||
|
ip: "1.2.3.4",
|
||||||
|
endpointPorts: []api.EndpointPort{{Name: "boo", Port: 7777, Protocol: "SCTP"}},
|
||||||
|
endpoints: nil,
|
||||||
|
expectCreate: &api.Endpoints{
|
||||||
|
ObjectMeta: om("boo"),
|
||||||
|
Subsets: []api.EndpointSubset{{
|
||||||
|
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||||
|
Ports: []api.EndpointPort{{Name: "boo", Port: 7777, Protocol: "SCTP"}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, test := range reconcile_tests {
|
for _, test := range reconcile_tests {
|
||||||
fakeClient := fake.NewSimpleClientset()
|
fakeClient := fake.NewSimpleClientset()
|
||||||
|
@ -1152,6 +1152,10 @@ func TestPrintHumanReadableService(t *testing.T) {
|
|||||||
Port: 8000,
|
Port: 8000,
|
||||||
Protocol: "TCP",
|
Protocol: "TCP",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Port: 7777,
|
||||||
|
Protocol: "SCTP",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -155,6 +155,12 @@ type KubeProxyConfiguration struct {
|
|||||||
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
||||||
// An empty string slice is meant to select all network interfaces.
|
// An empty string slice is meant to select all network interfaces.
|
||||||
NodePortAddresses []string
|
NodePortAddresses []string
|
||||||
|
// sctpUserSpaceNode is to enable the deployment of applications that use a userspace SCTP protocol implementation.
|
||||||
|
// If set to "true" the kube-proxy does not start listening on the host node on the SCTP ports of Services
|
||||||
|
// specified with externalIP or type=NodePort.
|
||||||
|
// If set to "false" kube-proxy listens on the SCTP ports of Services specified with externalIP or type=NodePort.
|
||||||
|
// Default value is "false".
|
||||||
|
SCTPUserSpaceNode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||||
|
@ -151,6 +151,12 @@ type KubeProxyConfiguration struct {
|
|||||||
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
||||||
// An empty string slice is meant to select all network interfaces.
|
// An empty string slice is meant to select all network interfaces.
|
||||||
NodePortAddresses []string `json:"nodePortAddresses"`
|
NodePortAddresses []string `json:"nodePortAddresses"`
|
||||||
|
// sctpUserSpaceNode is to enable the deployment of applications that use a userspace SCTP protocol implementation.
|
||||||
|
// If set to "true" the kube-proxy does not start listening on the host node on the SCTP ports of Services
|
||||||
|
// specified with externalIP or type=NodePort.
|
||||||
|
// If set to "false" kube-proxy listens on the SCTP ports of Services specified with externalIP or type=NodePort.
|
||||||
|
// Default value is "false".
|
||||||
|
SCTPUserSpaceNode bool `json:"sctpUserSpaceNode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||||
|
@ -144,6 +144,7 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_kubeproxyconfig_KubeProxyCon
|
|||||||
}
|
}
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||||
|
out.SCTPUserSpaceNode = in.SCTPUserSpaceNode
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +180,7 @@ func autoConvert_kubeproxyconfig_KubeProxyConfiguration_To_v1alpha1_KubeProxyCon
|
|||||||
}
|
}
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||||
|
out.SCTPUserSpaceNode = in.SCTPUserSpaceNode
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/ishidawataru/sctp"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@ -259,6 +260,10 @@ type Proxier struct {
|
|||||||
// networkInterfacer defines an interface for several net library functions.
|
// networkInterfacer defines an interface for several net library functions.
|
||||||
// Inject for test purpose.
|
// Inject for test purpose.
|
||||||
networkInterfacer utilproxy.NetworkInterfacer
|
networkInterfacer utilproxy.NetworkInterfacer
|
||||||
|
|
||||||
|
// Indicates whether a node is dedicated for applications that use userspace
|
||||||
|
// SCTP stack.
|
||||||
|
sctpUserSpaceNode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// listenPortOpener opens ports by calling bind() and listen().
|
// listenPortOpener opens ports by calling bind() and listen().
|
||||||
@ -290,6 +295,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
recorder record.EventRecorder,
|
recorder record.EventRecorder,
|
||||||
healthzServer healthcheck.HealthzUpdater,
|
healthzServer healthcheck.HealthzUpdater,
|
||||||
nodePortAddresses []string,
|
nodePortAddresses []string,
|
||||||
|
sctpUserSpaceNode bool,
|
||||||
) (*Proxier, error) {
|
) (*Proxier, error) {
|
||||||
// Set the route_localnet sysctl we need for
|
// Set the route_localnet sysctl we need for
|
||||||
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
||||||
@ -346,6 +352,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
nodePortAddresses: nodePortAddresses,
|
nodePortAddresses: nodePortAddresses,
|
||||||
networkInterfacer: utilproxy.RealNetwork{},
|
networkInterfacer: utilproxy.RealNetwork{},
|
||||||
|
sctpUserSpaceNode: sctpUserSpaceNode,
|
||||||
}
|
}
|
||||||
burstSyncs := 2
|
burstSyncs := 2
|
||||||
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
||||||
@ -845,9 +852,15 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
// If the "external" IP happens to be an IP that is local to this
|
// If the "external" IP happens to be an IP that is local to this
|
||||||
// machine, hold the local port open so no other process can open it
|
// machine, hold the local port open so no other process can open it
|
||||||
// (because the socket might open but it would never work).
|
// (because the socket might open but it would never work).
|
||||||
|
// Exception: if the node is dedicated for applications that use
|
||||||
|
// userspace SCTP stack we must not start listening on the local port
|
||||||
|
// in the kernel because that would load the SCTP kernel module, and
|
||||||
|
// there are interworking issues between the SCTP kernel module and
|
||||||
|
// userspace SCTP stacks.
|
||||||
if local, err := utilproxy.IsLocalIP(externalIP); err != nil {
|
if local, err := utilproxy.IsLocalIP(externalIP); err != nil {
|
||||||
glog.Errorf("can't determine if IP is local, assuming not: %v", err)
|
glog.Errorf("can't determine if IP is local, assuming not: %v", err)
|
||||||
} else if local {
|
} else if local && (svcInfo.GetProtocol() != api.ProtocolSCTP || !proxier.sctpUserSpaceNode) {
|
||||||
|
|
||||||
lp := utilproxy.LocalPort{
|
lp := utilproxy.LocalPort{
|
||||||
Description: "externalIP for " + svcNameString,
|
Description: "externalIP for " + svcNameString,
|
||||||
IP: externalIP,
|
IP: externalIP,
|
||||||
@ -1016,7 +1029,7 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
if proxier.portsMap[lp] != nil {
|
if proxier.portsMap[lp] != nil {
|
||||||
glog.V(4).Infof("Port %s was open before and is still needed", lp.String())
|
glog.V(4).Infof("Port %s was open before and is still needed", lp.String())
|
||||||
replacementPortsMap[lp] = proxier.portsMap[lp]
|
replacementPortsMap[lp] = proxier.portsMap[lp]
|
||||||
} else {
|
} else if svcInfo.GetProtocol() != api.ProtocolSCTP || !proxier.sctpUserSpaceNode {
|
||||||
socket, err := proxier.portMapper.OpenLocalPort(&lp)
|
socket, err := proxier.portMapper.OpenLocalPort(&lp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("can't open %s, skipping this nodePort: %v", lp.String(), err)
|
glog.Errorf("can't open %s, skipping this nodePort: %v", lp.String(), err)
|
||||||
@ -1419,6 +1432,18 @@ func openLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
socket = conn
|
socket = conn
|
||||||
|
case "sctp":
|
||||||
|
// There is not any golang/net way to bind or listen on an SCTP socket.
|
||||||
|
// We have to use a 3rd part lib - the same which is used in Docker
|
||||||
|
addr, err := sctp.ResolveSCTPAddr("sctp", net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := sctp.ListenSCTP("sctp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
socket = conn
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
|
return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,9 @@ func newFakeServiceInfo(service proxy.ServicePortName, ip net.IP, port int, prot
|
|||||||
|
|
||||||
func TestDeleteEndpointConnections(t *testing.T) {
|
func TestDeleteEndpointConnections(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
UDP = v1.ProtocolUDP
|
UDP = api.ProtocolUDP
|
||||||
TCP = v1.ProtocolTCP
|
TCP = api.ProtocolTCP
|
||||||
|
SCTP = api.ProtocolSCTP
|
||||||
)
|
)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
@ -188,6 +189,13 @@ func TestDeleteEndpointConnections(t *testing.T) {
|
|||||||
svcPort: 80,
|
svcPort: 80,
|
||||||
protocol: TCP,
|
protocol: TCP,
|
||||||
endpoint: "10.240.0.4:80",
|
endpoint: "10.240.0.4:80",
|
||||||
|
},{
|
||||||
|
description: "V4 SCTP",
|
||||||
|
svcName: "v4-sctp",
|
||||||
|
svcIP: "10.96.3.3",
|
||||||
|
svcPort: 80,
|
||||||
|
protocol: SCTP,
|
||||||
|
endpoint: "10.240.0.5:80",
|
||||||
},{
|
},{
|
||||||
description: "V4 UDP, nothing to delete, benign error",
|
description: "V4 UDP, nothing to delete, benign error",
|
||||||
svcName: "v4-udp-nothing-to-delete",
|
svcName: "v4-udp-nothing-to-delete",
|
||||||
@ -218,6 +226,13 @@ func TestDeleteEndpointConnections(t *testing.T) {
|
|||||||
svcPort: 80,
|
svcPort: 80,
|
||||||
protocol: TCP,
|
protocol: TCP,
|
||||||
endpoint: "[2001:db8::3]:80",
|
endpoint: "[2001:db8::3]:80",
|
||||||
|
}, {
|
||||||
|
description: "V6 SCTP",
|
||||||
|
svcName: "v6-sctp",
|
||||||
|
svcIP: "fd00:1234::40",
|
||||||
|
svcPort: 80,
|
||||||
|
protocol: SCTP,
|
||||||
|
endpoint: "[2001:db8::4]:80",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,6 +394,7 @@ func NewFakeProxier(ipt utiliptables.Interface) *Proxier {
|
|||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
nodePortAddresses: make([]string, 0),
|
nodePortAddresses: make([]string, 0),
|
||||||
networkInterfacer: utilproxytest.NewFakeNetwork(),
|
networkInterfacer: utilproxytest.NewFakeNetwork(),
|
||||||
|
sctpUserSpaceNode: false,
|
||||||
}
|
}
|
||||||
p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
|
p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
|
||||||
return p
|
return p
|
||||||
@ -1061,12 +1077,14 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
svc.Spec.ClusterIP = "172.16.55.4"
|
svc.Spec.ClusterIP = "172.16.55.4"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpport", "SCTP", 1236, 6321, 0)
|
||||||
}),
|
}),
|
||||||
makeTestService("somewhere-else", "node-port", func(svc *v1.Service) {
|
makeTestService("somewhere-else", "node-port", func(svc *v1.Service) {
|
||||||
svc.Spec.Type = v1.ServiceTypeNodePort
|
svc.Spec.Type = v1.ServiceTypeNodePort
|
||||||
svc.Spec.ClusterIP = "172.16.55.10"
|
svc.Spec.ClusterIP = "172.16.55.10"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blahblah", "UDP", 345, 678, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blahblah", "UDP", 345, 678, 0)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "muchmoreblah", "SCTP", 343, 676, 0)
|
||||||
}),
|
}),
|
||||||
makeTestService("somewhere", "load-balancer", func(svc *v1.Service) {
|
makeTestService("somewhere", "load-balancer", func(svc *v1.Service) {
|
||||||
svc.Spec.Type = v1.ServiceTypeLoadBalancer
|
svc.Spec.Type = v1.ServiceTypeLoadBalancer
|
||||||
@ -1100,8 +1118,8 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
fp.OnServiceAdd(services[i])
|
fp.OnServiceAdd(services[i])
|
||||||
}
|
}
|
||||||
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||||
if len(fp.serviceMap) != 8 {
|
if len(fp.serviceMap) != 10 {
|
||||||
t.Errorf("expected service map length 8, got %v", fp.serviceMap)
|
t.Errorf("expected service map length 10, got %v", fp.serviceMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The only-local-loadbalancer ones get added
|
// The only-local-loadbalancer ones get added
|
||||||
|
@ -64,6 +64,12 @@ const (
|
|||||||
|
|
||||||
kubeNodePortLocalSetUDPComment = "Kubernetes nodeport UDP port with externalTrafficPolicy=local"
|
kubeNodePortLocalSetUDPComment = "Kubernetes nodeport UDP port with externalTrafficPolicy=local"
|
||||||
kubeNodePortLocalSetUDP = "KUBE-NODE-PORT-LOCAL-UDP"
|
kubeNodePortLocalSetUDP = "KUBE-NODE-PORT-LOCAL-UDP"
|
||||||
|
|
||||||
|
kubeNodePortSetSCTPComment = "Kubernetes nodeport SCTP port for masquerade purpose"
|
||||||
|
kubeNodePortSetSCTP = "KUBE-NODE-PORT-SCTP"
|
||||||
|
|
||||||
|
kubeNodePortLocalSetSCTPComment = "Kubernetes nodeport SCTP port with externalTrafficPolicy=local"
|
||||||
|
kubeNodePortLocalSetSCTP = "KUBE-NODE-PORT-LOCAL-SCTP"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPSetVersioner can query the current ipset version.
|
// IPSetVersioner can query the current ipset version.
|
||||||
|
@ -179,6 +179,26 @@ func TestSyncIPSetEntries(t *testing.T) {
|
|||||||
currentEntries: []string{"80", "9090", "8081", "8082"},
|
currentEntries: []string{"80", "9090", "8081", "8082"},
|
||||||
expectedEntries: []string{"8080"},
|
expectedEntries: []string{"8080"},
|
||||||
},
|
},
|
||||||
|
{ // case 12
|
||||||
|
set: &utilipset.IPSet{
|
||||||
|
Name: "sctp-1",
|
||||||
|
},
|
||||||
|
setType: utilipset.HashIPPort,
|
||||||
|
ipv6: false,
|
||||||
|
activeEntries: []string{"172.17.0.4,sctp:80"},
|
||||||
|
currentEntries: nil,
|
||||||
|
expectedEntries: []string{"172.17.0.4,sctp:80"},
|
||||||
|
},
|
||||||
|
{ // case 1
|
||||||
|
set: &utilipset.IPSet{
|
||||||
|
Name: "sctp-2",
|
||||||
|
},
|
||||||
|
setType: utilipset.HashIPPort,
|
||||||
|
ipv6: true,
|
||||||
|
activeEntries: []string{"FE80::0202:B3FF:FE1E:8329,sctp:80"},
|
||||||
|
currentEntries: []string{"FE80::0202:B3FF:FE1E:8329,sctp:80"},
|
||||||
|
expectedEntries: []string{"FE80::0202:B3FF:FE1E:8329,sctp:80"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/ishidawataru/sctp"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@ -47,6 +48,8 @@ import (
|
|||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
|
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
|
||||||
utilexec "k8s.io/utils/exec"
|
utilexec "k8s.io/utils/exec"
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -128,6 +131,8 @@ var ipsetInfo = []struct {
|
|||||||
{kubeNodePortLocalSetTCP, utilipset.BitmapPort, false, kubeNodePortLocalSetTCPComment},
|
{kubeNodePortLocalSetTCP, utilipset.BitmapPort, false, kubeNodePortLocalSetTCPComment},
|
||||||
{kubeNodePortSetUDP, utilipset.BitmapPort, false, kubeNodePortSetUDPComment},
|
{kubeNodePortSetUDP, utilipset.BitmapPort, false, kubeNodePortSetUDPComment},
|
||||||
{kubeNodePortLocalSetUDP, utilipset.BitmapPort, false, kubeNodePortLocalSetUDPComment},
|
{kubeNodePortLocalSetUDP, utilipset.BitmapPort, false, kubeNodePortLocalSetUDPComment},
|
||||||
|
{kubeNodePortSetSCTP, utilipset.BitmapPort, false, kubeNodePortSetSCTPComment},
|
||||||
|
{kubeNodePortLocalSetSCTP, utilipset.BitmapPort, false, kubeNodePortLocalSetSCTPComment},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipsetWithIptablesChain is the ipsets list with iptables source chain and the chain jump to
|
// ipsetWithIptablesChain is the ipsets list with iptables source chain and the chain jump to
|
||||||
@ -152,6 +157,8 @@ var ipsetWithIptablesChain = []struct {
|
|||||||
{kubeNodePortSetTCP, string(KubeNodePortChain), string(KubeMarkMasqChain), "dst", "tcp"},
|
{kubeNodePortSetTCP, string(KubeNodePortChain), string(KubeMarkMasqChain), "dst", "tcp"},
|
||||||
{kubeNodePortLocalSetUDP, string(KubeNodePortChain), "RETURN", "dst", "udp"},
|
{kubeNodePortLocalSetUDP, string(KubeNodePortChain), "RETURN", "dst", "udp"},
|
||||||
{kubeNodePortSetUDP, string(KubeNodePortChain), string(KubeMarkMasqChain), "dst", "udp"},
|
{kubeNodePortSetUDP, string(KubeNodePortChain), string(KubeMarkMasqChain), "dst", "udp"},
|
||||||
|
{kubeNodePortSetSCTP, string(kubeServicesChain), string(KubeNodePortChain), "dst", "sctp"},
|
||||||
|
{kubeNodePortLocalSetSCTP, string(KubeNodePortChain), "RETURN", "dst", "sctp"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipvsModules = []string{
|
var ipvsModules = []string{
|
||||||
@ -227,6 +234,7 @@ type Proxier struct {
|
|||||||
// networkInterfacer defines an interface for several net library functions.
|
// networkInterfacer defines an interface for several net library functions.
|
||||||
// Inject for test purpose.
|
// Inject for test purpose.
|
||||||
networkInterfacer utilproxy.NetworkInterfacer
|
networkInterfacer utilproxy.NetworkInterfacer
|
||||||
|
sctpUserSpaceNode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPGetter helps get node network interface IP
|
// IPGetter helps get node network interface IP
|
||||||
@ -292,6 +300,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
healthzServer healthcheck.HealthzUpdater,
|
healthzServer healthcheck.HealthzUpdater,
|
||||||
scheduler string,
|
scheduler string,
|
||||||
nodePortAddresses []string,
|
nodePortAddresses []string,
|
||||||
|
sctpUserSpaceNode bool,
|
||||||
) (*Proxier, error) {
|
) (*Proxier, error) {
|
||||||
// Set the route_localnet sysctl we need for
|
// Set the route_localnet sysctl we need for
|
||||||
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
||||||
@ -373,6 +382,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
ipset: ipset,
|
ipset: ipset,
|
||||||
nodePortAddresses: nodePortAddresses,
|
nodePortAddresses: nodePortAddresses,
|
||||||
networkInterfacer: utilproxy.RealNetwork{},
|
networkInterfacer: utilproxy.RealNetwork{},
|
||||||
|
sctpUserSpaceNode: sctpUserSpaceNode,
|
||||||
}
|
}
|
||||||
// initialize ipsetList with all sets we needed
|
// initialize ipsetList with all sets we needed
|
||||||
proxier.ipsetList = make(map[string]*IPSet)
|
proxier.ipsetList = make(map[string]*IPSet)
|
||||||
@ -805,7 +815,7 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
for _, externalIP := range svcInfo.ExternalIPs {
|
for _, externalIP := range svcInfo.ExternalIPs {
|
||||||
if local, err := utilproxy.IsLocalIP(externalIP); err != nil {
|
if local, err := utilproxy.IsLocalIP(externalIP); err != nil {
|
||||||
glog.Errorf("can't determine if IP is local, assuming not: %v", err)
|
glog.Errorf("can't determine if IP is local, assuming not: %v", err)
|
||||||
} else if local {
|
} else if local && (svcInfo.GetProtocol() != api.ProtocolSCTP || !proxier.sctpUserSpaceNode) {
|
||||||
lp := utilproxy.LocalPort{
|
lp := utilproxy.LocalPort{
|
||||||
Description: "externalIP for " + svcNameString,
|
Description: "externalIP for " + svcNameString,
|
||||||
IP: externalIP,
|
IP: externalIP,
|
||||||
@ -1004,7 +1014,7 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
if proxier.portsMap[lp] != nil {
|
if proxier.portsMap[lp] != nil {
|
||||||
glog.V(4).Infof("Port %s was open before and is still needed", lp.String())
|
glog.V(4).Infof("Port %s was open before and is still needed", lp.String())
|
||||||
replacementPortsMap[lp] = proxier.portsMap[lp]
|
replacementPortsMap[lp] = proxier.portsMap[lp]
|
||||||
} else {
|
} else if svcInfo.GetProtocol() != api.ProtocolSCTP || !proxier.sctpUserSpaceNode {
|
||||||
socket, err := proxier.portMapper.OpenLocalPort(&lp)
|
socket, err := proxier.portMapper.OpenLocalPort(&lp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("can't open %s, skipping this nodePort: %v", lp.String(), err)
|
glog.Errorf("can't open %s, skipping this nodePort: %v", lp.String(), err)
|
||||||
@ -1032,6 +1042,8 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
nodePortSet = proxier.ipsetList[kubeNodePortSetTCP]
|
nodePortSet = proxier.ipsetList[kubeNodePortSetTCP]
|
||||||
case "udp":
|
case "udp":
|
||||||
nodePortSet = proxier.ipsetList[kubeNodePortSetUDP]
|
nodePortSet = proxier.ipsetList[kubeNodePortSetUDP]
|
||||||
|
case "sctp":
|
||||||
|
nodePortSet = proxier.ipsetList[kubeNodePortSetSCTP]
|
||||||
default:
|
default:
|
||||||
// It should never hit
|
// It should never hit
|
||||||
glog.Errorf("Unsupported protocol type: %s", protocol)
|
glog.Errorf("Unsupported protocol type: %s", protocol)
|
||||||
@ -1052,6 +1064,8 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
nodePortLocalSet = proxier.ipsetList[kubeNodePortLocalSetTCP]
|
nodePortLocalSet = proxier.ipsetList[kubeNodePortLocalSetTCP]
|
||||||
case "udp":
|
case "udp":
|
||||||
nodePortLocalSet = proxier.ipsetList[kubeNodePortLocalSetUDP]
|
nodePortLocalSet = proxier.ipsetList[kubeNodePortLocalSetUDP]
|
||||||
|
case "sctp":
|
||||||
|
nodePortLocalSet = proxier.ipsetList[kubeNodePortLocalSetSCTP]
|
||||||
default:
|
default:
|
||||||
// It should never hit
|
// It should never hit
|
||||||
glog.Errorf("Unsupported protocol type: %s", protocol)
|
glog.Errorf("Unsupported protocol type: %s", protocol)
|
||||||
@ -1636,6 +1650,18 @@ func openLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
socket = conn
|
socket = conn
|
||||||
|
case "sctp":
|
||||||
|
// SCTP is not supported by golang/net, or any other built-in lib,
|
||||||
|
// so we have to manage SCTP via a 3rd party lib.
|
||||||
|
sctpAddr, err := sctp.ResolveSCTPAddr("sctp", net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := sctp.ListenSCTP("sctp", sctpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
socket = conn
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
|
return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset u
|
|||||||
ipsetList: ipsetList,
|
ipsetList: ipsetList,
|
||||||
nodePortAddresses: make([]string, 0),
|
nodePortAddresses: make([]string, 0),
|
||||||
networkInterfacer: proxyutiltest.NewFakeNetwork(),
|
networkInterfacer: proxyutiltest.NewFakeNetwork(),
|
||||||
|
sctpUserSpaceNode: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1345,12 +1346,14 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
svc.Spec.ClusterIP = "172.16.55.4"
|
svc.Spec.ClusterIP = "172.16.55.4"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somesctp", "SCTP", 1236, 6321, 0)
|
||||||
}),
|
}),
|
||||||
makeTestService("somewhere-else", "node-port", func(svc *v1.Service) {
|
makeTestService("somewhere-else", "node-port", func(svc *v1.Service) {
|
||||||
svc.Spec.Type = v1.ServiceTypeNodePort
|
svc.Spec.Type = v1.ServiceTypeNodePort
|
||||||
svc.Spec.ClusterIP = "172.16.55.10"
|
svc.Spec.ClusterIP = "172.16.55.10"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blahblah", "UDP", 345, 678, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blahblah", "UDP", 345, 678, 0)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpblah", "SCTP", 343, 676, 0)
|
||||||
}),
|
}),
|
||||||
makeTestService("somewhere", "load-balancer", func(svc *v1.Service) {
|
makeTestService("somewhere", "load-balancer", func(svc *v1.Service) {
|
||||||
svc.Spec.Type = v1.ServiceTypeLoadBalancer
|
svc.Spec.Type = v1.ServiceTypeLoadBalancer
|
||||||
@ -1358,8 +1361,9 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar", "UDP", 8675, 30061, 7000)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar", "UDP", 8675, 30061, 7000)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8676, 30062, 7001)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8676, 30062, 7001)
|
||||||
svc.Status.LoadBalancer = v1.LoadBalancerStatus{
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpfoo", "SCTP", 8677, 30063, 7002)
|
||||||
Ingress: []v1.LoadBalancerIngress{
|
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
{IP: "10.1.2.4"},
|
{IP: "10.1.2.4"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1370,8 +1374,9 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar2", "UDP", 8677, 30063, 7002)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar2", "UDP", 8677, 30063, 7002)
|
||||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8678, 30064, 7003)
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8678, 30064, 7003)
|
||||||
svc.Status.LoadBalancer = v1.LoadBalancerStatus{
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpbaz", "SCTP", 8679, 30065, 7004)
|
||||||
Ingress: []v1.LoadBalancerIngress{
|
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
{IP: "10.1.2.3"},
|
{IP: "10.1.2.3"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1384,8 +1389,8 @@ func TestBuildServiceMapAddRemove(t *testing.T) {
|
|||||||
fp.OnServiceAdd(services[i])
|
fp.OnServiceAdd(services[i])
|
||||||
}
|
}
|
||||||
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||||
if len(fp.serviceMap) != 8 {
|
if len(fp.serviceMap) != 12 {
|
||||||
t.Errorf("expected service map length 8, got %v", fp.serviceMap)
|
t.Errorf("expected service map length 12, got %v", fp.serviceMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The only-local-loadbalancer ones get added
|
// The only-local-loadbalancer ones get added
|
||||||
@ -1455,6 +1460,11 @@ func TestBuildServiceMapServiceHeadless(t *testing.T) {
|
|||||||
svc.Spec.Type = v1.ServiceTypeClusterIP
|
svc.Spec.Type = v1.ServiceTypeClusterIP
|
||||||
svc.Spec.ClusterIP = v1.ClusterIPNone
|
svc.Spec.ClusterIP = v1.ClusterIPNone
|
||||||
}),
|
}),
|
||||||
|
makeTestService("somewhere-else", "headless-sctp", func(svc *api.Service) {
|
||||||
|
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||||
|
svc.Spec.ClusterIP = api.ClusterIPNone
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 1235, 0, 0)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Headless service should be ignored
|
// Headless service should be ignored
|
||||||
@ -2620,6 +2630,76 @@ func Test_syncService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
bindAddr: true,
|
bindAddr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// case 4, SCTP, old virtual server is same as new virtual server
|
||||||
|
oldVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 80,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
svcName: "foo",
|
||||||
|
newVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 80,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
bindAddr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// case 5, old virtual server is different from new virtual server
|
||||||
|
oldVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 8080,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
svcName: "bar",
|
||||||
|
newVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 8080,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagPersistent,
|
||||||
|
},
|
||||||
|
bindAddr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// case 6, old virtual server is different from new virtual server
|
||||||
|
oldVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 8080,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
svcName: "bar",
|
||||||
|
newVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 8080,
|
||||||
|
Scheduler: "wlc",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
bindAddr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// case 7, old virtual server is nil, and create new virtual server
|
||||||
|
oldVirtualServer: nil,
|
||||||
|
svcName: "baz",
|
||||||
|
newVirtualServer: &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: string(api.ProtocolSCTP),
|
||||||
|
Port: 53,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: utilipvs.FlagHashed,
|
||||||
|
},
|
||||||
|
bindAddr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
@ -2748,6 +2828,7 @@ func TestCleanLegacyService(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
DefaultScheduler,
|
DefaultScheduler,
|
||||||
make([]string, 0),
|
make([]string, 0),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
@ -114,6 +114,15 @@ func TestServiceToServiceMap(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
expected: map[ServicePortName]*BaseServiceInfo{},
|
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "headless sctp service",
|
||||||
|
service: makeTestService("ns2", "headless", func(svc *api.Service) {
|
||||||
|
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||||
|
svc.Spec.ClusterIP = api.ClusterIPNone
|
||||||
|
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 7777, 0, 0)
|
||||||
|
}),
|
||||||
|
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "headless service without port",
|
desc: "headless service without port",
|
||||||
service: makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
|
service: makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
|
||||||
|
@ -68,6 +68,8 @@ func newProxySocket(protocol v1.Protocol, ip net.IP, port int) (ProxySocket, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &udpProxySocket{UDPConn: conn, port: port}, nil
|
return &udpProxySocket{UDPConn: conn, port: port}, nil
|
||||||
|
case "SCTP":
|
||||||
|
return nil, fmt.Errorf("SCTP is not supported for user space proxy")
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown protocol %q", protocol)
|
return nil, fmt.Errorf("unknown protocol %q", protocol)
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ func TestLocalPortString(t *testing.T) {
|
|||||||
{"IPv4 UDP", "1.2.3.4", 9999, "udp", "\"IPv4 UDP\" (1.2.3.4:9999/udp)"},
|
{"IPv4 UDP", "1.2.3.4", 9999, "udp", "\"IPv4 UDP\" (1.2.3.4:9999/udp)"},
|
||||||
{"IPv4 TCP", "5.6.7.8", 1053, "tcp", "\"IPv4 TCP\" (5.6.7.8:1053/tcp)"},
|
{"IPv4 TCP", "5.6.7.8", 1053, "tcp", "\"IPv4 TCP\" (5.6.7.8:1053/tcp)"},
|
||||||
{"IPv6 TCP", "2001:db8::1", 80, "tcp", "\"IPv6 TCP\" ([2001:db8::1]:80/tcp)"},
|
{"IPv6 TCP", "2001:db8::1", 80, "tcp", "\"IPv6 TCP\" ([2001:db8::1]:80/tcp)"},
|
||||||
|
{"IPv4 SCTP", "9.10.11.12", 7777, "sctp", "\"IPv4 SCTP\" (9.10.11.12:7777/sctp)"},
|
||||||
|
{"IPv6 SCTP", "2001:db8::2", 80, "sctp", "\"IPv6 SCTP\" ([2001:db8::2]:80/sctp)"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -428,6 +428,9 @@ func Enum(p v1.Protocol) uint16 {
|
|||||||
if p == v1.ProtocolUDP {
|
if p == v1.ProtocolUDP {
|
||||||
return 17
|
return 17
|
||||||
}
|
}
|
||||||
|
if p == api.ProtocolSCTP {
|
||||||
|
return 132
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +101,8 @@ func newProxySocket(protocol v1.Protocol, ip net.IP, port int) (proxySocket, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &udpProxySocket{UDPConn: conn, port: port}, nil
|
return &udpProxySocket{UDPConn: conn, port: port}, nil
|
||||||
|
case "SCTP":
|
||||||
|
return nil, fmt.Errorf("SCTP is not supported for user space proxy")
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown protocol %q", protocol)
|
return nil, fmt.Errorf("unknown protocol %q", protocol)
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ type Entry struct {
|
|||||||
// Port is the entry's Port.
|
// Port is the entry's Port.
|
||||||
Port int
|
Port int
|
||||||
// Protocol is the entry's Protocol. The protocols of entries in the same ip set are all
|
// Protocol is the entry's Protocol. The protocols of entries in the same ip set are all
|
||||||
// the same. The accepted protocols are TCP and UDP.
|
// the same. The accepted protocols are TCP, UDP and SCTP.
|
||||||
Protocol string
|
Protocol string
|
||||||
// Net is the entry's IP network address. Network address with zero prefix size can NOT
|
// Net is the entry's IP network address. Network address with zero prefix size can NOT
|
||||||
// be stored.
|
// be stored.
|
||||||
@ -482,10 +482,10 @@ func IsNotFoundError(err error) bool {
|
|||||||
|
|
||||||
// checks if given protocol is supported in entry
|
// checks if given protocol is supported in entry
|
||||||
func validateProtocol(protocol string) bool {
|
func validateProtocol(protocol string) bool {
|
||||||
if protocol == ProtocolTCP || protocol == ProtocolUDP {
|
if protocol == ProtocolTCP || protocol == ProtocolUDP || protocol == ProtocolSCTP {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
glog.Errorf("Invalid entry's protocol: %s, supported protocols are [%s, %s]", protocol, ProtocolTCP, ProtocolUDP)
|
glog.Errorf("Invalid entry's protocol: %s, supported protocols are [%s, %s]", protocol, ProtocolTCP, ProtocolUDP, ProtocolSCTP)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,6 +346,22 @@ var testCases = []struct {
|
|||||||
},
|
},
|
||||||
delCombinedOutputLog: []string{"ipset", "del", "SIX", "80"},
|
delCombinedOutputLog: []string{"ipset", "del", "SIX", "80"},
|
||||||
},
|
},
|
||||||
|
{ // case 7
|
||||||
|
entry: &Entry{
|
||||||
|
IP: "192.168.1.2",
|
||||||
|
Port: 80,
|
||||||
|
Protocol: ProtocolSCTP,
|
||||||
|
SetType: HashIPPort,
|
||||||
|
},
|
||||||
|
set: &IPSet{
|
||||||
|
Name: "SETTE",
|
||||||
|
},
|
||||||
|
addCombinedOutputLog: [][]string{
|
||||||
|
{"ipset", "add", "SETTE", "192.168.1.2,sctp:80"},
|
||||||
|
{"ipset", "add", "SETTE", "192.168.1.2,sctp:80", "-exist"},
|
||||||
|
},
|
||||||
|
delCombinedOutputLog: []string{"ipset", "del", "SETTE", "192.168.1.2,sctp:80"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddEntry(t *testing.T) {
|
func TestAddEntry(t *testing.T) {
|
||||||
@ -755,6 +771,10 @@ func Test_validateFamily(t *testing.T) {
|
|||||||
family: "",
|
family: "",
|
||||||
valid: false,
|
valid: false,
|
||||||
},
|
},
|
||||||
|
{ // case[8]
|
||||||
|
family: "sctp",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
valid := validateHashFamily(testCases[i].family)
|
valid := validateHashFamily(testCases[i].family)
|
||||||
@ -804,6 +824,10 @@ func Test_validateProtocol(t *testing.T) {
|
|||||||
protocol: "",
|
protocol: "",
|
||||||
valid: false,
|
valid: false,
|
||||||
},
|
},
|
||||||
|
{ // case[8]
|
||||||
|
protocol: ProtocolSCTP,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
valid := validateProtocol(testCases[i].protocol)
|
valid := validateProtocol(testCases[i].protocol)
|
||||||
@ -1403,14 +1427,14 @@ func TestValidateEntry(t *testing.T) {
|
|||||||
entry: &Entry{
|
entry: &Entry{
|
||||||
SetType: HashIPPortIP,
|
SetType: HashIPPortIP,
|
||||||
IP: "10.20.30.40",
|
IP: "10.20.30.40",
|
||||||
Protocol: "SCTP ",
|
Protocol: ProtocolSCTP,
|
||||||
Port: 8090,
|
Port: 8090,
|
||||||
IP2: "10.20.30.41",
|
IP2: "10.20.30.41",
|
||||||
},
|
},
|
||||||
set: &IPSet{
|
set: &IPSet{
|
||||||
Name: "unsupported-protocol",
|
Name: "sctp",
|
||||||
},
|
},
|
||||||
valid: false,
|
valid: true,
|
||||||
},
|
},
|
||||||
{ // case[20]
|
{ // case[20]
|
||||||
entry: &Entry{
|
entry: &Entry{
|
||||||
|
@ -49,6 +49,8 @@ const (
|
|||||||
ProtocolTCP = "tcp"
|
ProtocolTCP = "tcp"
|
||||||
// ProtocolUDP represents UDP protocol.
|
// ProtocolUDP represents UDP protocol.
|
||||||
ProtocolUDP = "udp"
|
ProtocolUDP = "udp"
|
||||||
|
// ProtocolSCTP represents SCTP protocol.
|
||||||
|
ProtocolSCTP = "sctp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidIPSetTypes defines the supported ip set type.
|
// ValidIPSetTypes defines the supported ip set type.
|
||||||
|
@ -252,6 +252,8 @@ func stringToProtocol(protocol string) uint16 {
|
|||||||
return uint16(syscall.IPPROTO_TCP)
|
return uint16(syscall.IPPROTO_TCP)
|
||||||
case "udp":
|
case "udp":
|
||||||
return uint16(syscall.IPPROTO_UDP)
|
return uint16(syscall.IPPROTO_UDP)
|
||||||
|
case "sctp":
|
||||||
|
return uint16(syscall.IPPROTO_SCTP)
|
||||||
}
|
}
|
||||||
return uint16(0)
|
return uint16(0)
|
||||||
}
|
}
|
||||||
@ -263,6 +265,8 @@ func protocolToString(proto Protocol) string {
|
|||||||
return "TCP"
|
return "TCP"
|
||||||
case syscall.IPPROTO_UDP:
|
case syscall.IPPROTO_UDP:
|
||||||
return "UDP"
|
return "UDP"
|
||||||
|
case syscall.IPPROTO_SCTP:
|
||||||
|
return "SCTP"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,30 @@ func Test_toVirtualServer(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
libipvs.Service{
|
||||||
|
Protocol: syscall.IPPROTO_SCTP,
|
||||||
|
Port: 80,
|
||||||
|
FWMark: 0,
|
||||||
|
SchedName: "",
|
||||||
|
Flags: uint32(FlagPersistent + FlagHashed),
|
||||||
|
Timeout: 0,
|
||||||
|
Netmask: 0xffffffff,
|
||||||
|
AddressFamily: syscall.AF_INET,
|
||||||
|
Address: nil,
|
||||||
|
PEName: "",
|
||||||
|
},
|
||||||
|
VirtualServer{
|
||||||
|
Address: net.ParseIP("0.0.0.0"),
|
||||||
|
Protocol: "SCTP",
|
||||||
|
Port: 80,
|
||||||
|
Scheduler: "",
|
||||||
|
Flags: ServiceFlags(FlagPersistent),
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range Tests {
|
for i := range Tests {
|
||||||
@ -359,10 +383,10 @@ func Test_toIPVSDestination(t *testing.T) {
|
|||||||
|
|
||||||
func Test_stringToProtocol(t *testing.T) {
|
func Test_stringToProtocol(t *testing.T) {
|
||||||
tests := []string{
|
tests := []string{
|
||||||
"TCP", "UDP", "ICMP",
|
"TCP", "UDP", "ICMP", "SCTP",
|
||||||
}
|
}
|
||||||
expected := []uint16{
|
expected := []uint16{
|
||||||
uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0),
|
uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0), uint16(syscall.IPPROTO_SCTP),
|
||||||
}
|
}
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
got := stringToProtocol(tests[i])
|
got := stringToProtocol(tests[i])
|
||||||
@ -375,10 +399,10 @@ func Test_stringToProtocol(t *testing.T) {
|
|||||||
|
|
||||||
func Test_protocolToString(t *testing.T) {
|
func Test_protocolToString(t *testing.T) {
|
||||||
tests := []Protocol{
|
tests := []Protocol{
|
||||||
syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, Protocol(0),
|
syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, Protocol(0), syscall.IPPROTO_SCTP,
|
||||||
}
|
}
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"TCP", "UDP", "",
|
"TCP", "UDP", "", "SCTP",
|
||||||
}
|
}
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
got := protocolToString(tests[i])
|
got := protocolToString(tests[i])
|
||||||
|
@ -188,6 +188,46 @@ func TestVirtualServerEqual(t *testing.T) {
|
|||||||
equal: true,
|
equal: true,
|
||||||
reason: "All fields equal",
|
reason: "All fields equal",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
svcA: &VirtualServer{
|
||||||
|
Address: net.ParseIP("2012::beef"),
|
||||||
|
Protocol: "TCP",
|
||||||
|
Port: 0,
|
||||||
|
Scheduler: "wrr",
|
||||||
|
Flags: 0,
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
svcB: &VirtualServer{
|
||||||
|
Address: net.ParseIP("2012::beeef"),
|
||||||
|
Protocol: "SCTP",
|
||||||
|
Port: 0,
|
||||||
|
Scheduler: "wrr",
|
||||||
|
Flags: 0,
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
equal: false,
|
||||||
|
reason: "Protocol not equal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
svcA: &VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: "SCTP",
|
||||||
|
Port: 80,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: 0x1,
|
||||||
|
Timeout: 10800,
|
||||||
|
},
|
||||||
|
svcB: &VirtualServer{
|
||||||
|
Address: net.ParseIP("1.2.3.4"),
|
||||||
|
Protocol: "SCTP",
|
||||||
|
Port: 80,
|
||||||
|
Scheduler: "rr",
|
||||||
|
Flags: 0x1,
|
||||||
|
Timeout: 10800,
|
||||||
|
},
|
||||||
|
equal: true,
|
||||||
|
reason: "All fields equal",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range Tests {
|
for i := range Tests {
|
||||||
|
@ -71,12 +71,22 @@ func TestVirtualServer(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error when add virtual server, error: %v", err)
|
t.Errorf("Unexpected error when add virtual server, error: %v", err)
|
||||||
}
|
}
|
||||||
|
// Add another virtual server
|
||||||
|
vs3 := &utilipvs.VirtualServer{
|
||||||
|
Address: net.ParseIP("10::40"),
|
||||||
|
Port: uint16(7777),
|
||||||
|
Protocol: string("SCTP"),
|
||||||
|
}
|
||||||
|
err = fake.AddVirtualServer(vs3)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error when add virtual server, error: %v", err)
|
||||||
|
}
|
||||||
// List all virtual servers
|
// List all virtual servers
|
||||||
list, err := fake.GetVirtualServers()
|
list, err := fake.GetVirtualServers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Fail to list virtual servers, error: %v", err)
|
t.Errorf("Fail to list virtual servers, error: %v", err)
|
||||||
}
|
}
|
||||||
if len(list) != 2 {
|
if len(list) != 3 {
|
||||||
t.Errorf("Expect 2 virtual servers, got: %d", len(list))
|
t.Errorf("Expect 2 virtual servers, got: %d", len(list))
|
||||||
}
|
}
|
||||||
// Delete a virtual server
|
// Delete a virtual server
|
||||||
|
@ -749,7 +749,7 @@ message ContainerPort {
|
|||||||
// This must be a valid port number, 0 < x < 65536.
|
// This must be a valid port number, 0 < x < 65536.
|
||||||
optional int32 containerPort = 3;
|
optional int32 containerPort = 3;
|
||||||
|
|
||||||
// Protocol for port. Must be UDP or TCP.
|
// Protocol for port. Must be UDP, TCP, or SCTP.
|
||||||
// Defaults to "TCP".
|
// Defaults to "TCP".
|
||||||
// +optional
|
// +optional
|
||||||
optional string protocol = 4;
|
optional string protocol = 4;
|
||||||
@ -968,7 +968,7 @@ message EndpointPort {
|
|||||||
optional int32 port = 2;
|
optional int32 port = 2;
|
||||||
|
|
||||||
// The IP protocol for this port.
|
// The IP protocol for this port.
|
||||||
// Must be UDP or TCP.
|
// Must be UDP, TCP, or SCTP.
|
||||||
// Default is TCP.
|
// Default is TCP.
|
||||||
// +optional
|
// +optional
|
||||||
optional string protocol = 3;
|
optional string protocol = 3;
|
||||||
@ -4148,7 +4148,7 @@ message ServicePort {
|
|||||||
// +optional
|
// +optional
|
||||||
optional string name = 1;
|
optional string name = 1;
|
||||||
|
|
||||||
// The IP protocol for this port. Supports "TCP" and "UDP".
|
// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
|
||||||
// Default is TCP.
|
// Default is TCP.
|
||||||
// +optional
|
// +optional
|
||||||
optional string protocol = 2;
|
optional string protocol = 2;
|
||||||
|
@ -861,6 +861,8 @@ const (
|
|||||||
ProtocolTCP Protocol = "TCP"
|
ProtocolTCP Protocol = "TCP"
|
||||||
// ProtocolUDP is the UDP protocol.
|
// ProtocolUDP is the UDP protocol.
|
||||||
ProtocolUDP Protocol = "UDP"
|
ProtocolUDP Protocol = "UDP"
|
||||||
|
// ProtocolSCTP is the SCTP protocol.
|
||||||
|
ProtocolSCTP Protocol = "SCTP"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Represents a Persistent Disk resource in Google Compute Engine.
|
// Represents a Persistent Disk resource in Google Compute Engine.
|
||||||
@ -1662,7 +1664,7 @@ type ContainerPort struct {
|
|||||||
// Number of port to expose on the pod's IP address.
|
// Number of port to expose on the pod's IP address.
|
||||||
// This must be a valid port number, 0 < x < 65536.
|
// This must be a valid port number, 0 < x < 65536.
|
||||||
ContainerPort int32 `json:"containerPort" protobuf:"varint,3,opt,name=containerPort"`
|
ContainerPort int32 `json:"containerPort" protobuf:"varint,3,opt,name=containerPort"`
|
||||||
// Protocol for port. Must be UDP or TCP.
|
// Protocol for port. Must be UDP, TCP, or SCTP. "SCTP" is supported only if "HostPort" is not specified.
|
||||||
// Defaults to "TCP".
|
// Defaults to "TCP".
|
||||||
// +optional
|
// +optional
|
||||||
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol,casttype=Protocol"`
|
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol,casttype=Protocol"`
|
||||||
@ -3515,7 +3517,7 @@ type ServicePort struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
|
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
|
||||||
|
|
||||||
// The IP protocol for this port. Supports "TCP" and "UDP".
|
// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
|
||||||
// Default is TCP.
|
// Default is TCP.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"`
|
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"`
|
||||||
@ -3729,7 +3731,7 @@ type EndpointPort struct {
|
|||||||
Port int32 `json:"port" protobuf:"varint,2,opt,name=port"`
|
Port int32 `json:"port" protobuf:"varint,2,opt,name=port"`
|
||||||
|
|
||||||
// The IP protocol for this port.
|
// The IP protocol for this port.
|
||||||
// Must be UDP or TCP.
|
// Must be UDP, TCP, or SCTP.
|
||||||
// Default is TCP.
|
// Default is TCP.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,3,opt,name=protocol,casttype=Protocol"`
|
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,3,opt,name=protocol,casttype=Protocol"`
|
||||||
|
@ -353,7 +353,7 @@ var map_ContainerPort = map[string]string{
|
|||||||
"name": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services.",
|
"name": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services.",
|
||||||
"hostPort": "Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this.",
|
"hostPort": "Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this.",
|
||||||
"containerPort": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536.",
|
"containerPort": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536.",
|
||||||
"protocol": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\".",
|
"protocol": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\".",
|
||||||
"hostIP": "What host IP to bind the external port to.",
|
"hostIP": "What host IP to bind the external port to.",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,7 +488,7 @@ var map_EndpointPort = map[string]string{
|
|||||||
"": "EndpointPort is a tuple that describes a single port.",
|
"": "EndpointPort is a tuple that describes a single port.",
|
||||||
"name": "The name of this port (corresponds to ServicePort.Name). Must be a DNS_LABEL. Optional only if one port is defined.",
|
"name": "The name of this port (corresponds to ServicePort.Name). Must be a DNS_LABEL. Optional only if one port is defined.",
|
||||||
"port": "The port number of the endpoint.",
|
"port": "The port number of the endpoint.",
|
||||||
"protocol": "The IP protocol for this port. Must be UDP or TCP. Default is TCP.",
|
"protocol": "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (EndpointPort) SwaggerDoc() map[string]string {
|
func (EndpointPort) SwaggerDoc() map[string]string {
|
||||||
@ -2058,7 +2058,7 @@ func (ServiceList) SwaggerDoc() map[string]string {
|
|||||||
var map_ServicePort = map[string]string{
|
var map_ServicePort = map[string]string{
|
||||||
"": "ServicePort contains information on service's port.",
|
"": "ServicePort contains information on service's port.",
|
||||||
"name": "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects. Optional if only one ServicePort is defined on this service.",
|
"name": "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects. Optional if only one ServicePort is defined on this service.",
|
||||||
"protocol": "The IP protocol for this port. Supports \"TCP\" and \"UDP\". Default is TCP.",
|
"protocol": "The IP protocol for this port. Supports \"TCP\", \"UDP\", and \"SCTP\". Default is TCP.",
|
||||||
"port": "The port that will be exposed by this service.",
|
"port": "The port that will be exposed by this service.",
|
||||||
"targetPort": "Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service",
|
"targetPort": "Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service",
|
||||||
"nodePort": "The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system. If specified, it will be allocated to the service if unused or else creation of the service will fail. Default is to auto-allocate a port if the ServiceType of this Service requires one. More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport",
|
"nodePort": "The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system. If specified, it will be allocated to the service if unused or else creation of the service will fail. Default is to auto-allocate a port if the ServiceType of this Service requires one. More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport",
|
||||||
|
@ -712,7 +712,7 @@ message NetworkPolicyPeer {
|
|||||||
|
|
||||||
// DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.
|
// DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.
|
||||||
message NetworkPolicyPort {
|
message NetworkPolicyPort {
|
||||||
// Optional. The protocol (TCP or UDP) which traffic must match.
|
// Optional. The protocol (TCP, UDP, or SCTP) which traffic must match.
|
||||||
// If not specified, this field defaults to TCP.
|
// If not specified, this field defaults to TCP.
|
||||||
// +optional
|
// +optional
|
||||||
optional string protocol = 1;
|
optional string protocol = 1;
|
||||||
|
@ -1275,7 +1275,7 @@ type NetworkPolicyEgressRule struct {
|
|||||||
|
|
||||||
// DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.
|
// DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.
|
||||||
type NetworkPolicyPort struct {
|
type NetworkPolicyPort struct {
|
||||||
// Optional. The protocol (TCP or UDP) which traffic must match.
|
// Optional. The protocol (TCP, UDP, or SCTP) which traffic must match.
|
||||||
// If not specified, this field defaults to TCP.
|
// If not specified, this field defaults to TCP.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol *v1.Protocol `json:"protocol,omitempty" protobuf:"bytes,1,opt,name=protocol,casttype=k8s.io/api/core/v1.Protocol"`
|
Protocol *v1.Protocol `json:"protocol,omitempty" protobuf:"bytes,1,opt,name=protocol,casttype=k8s.io/api/core/v1.Protocol"`
|
||||||
|
@ -419,7 +419,7 @@ func (NetworkPolicyPeer) SwaggerDoc() map[string]string {
|
|||||||
|
|
||||||
var map_NetworkPolicyPort = map[string]string{
|
var map_NetworkPolicyPort = map[string]string{
|
||||||
"": "DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.",
|
"": "DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort.",
|
||||||
"protocol": "Optional. The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.",
|
"protocol": "Optional. The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.",
|
||||||
"port": "If specified, the port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers. If present, only traffic on the specified protocol AND port will be matched.",
|
"port": "If specified, the port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers. If present, only traffic on the specified protocol AND port will be matched.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ message NetworkPolicyPeer {
|
|||||||
|
|
||||||
// NetworkPolicyPort describes a port to allow traffic on
|
// NetworkPolicyPort describes a port to allow traffic on
|
||||||
message NetworkPolicyPort {
|
message NetworkPolicyPort {
|
||||||
// The protocol (TCP or UDP) which traffic must match. If not specified, this
|
// The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this
|
||||||
// field defaults to TCP.
|
// field defaults to TCP.
|
||||||
// +optional
|
// +optional
|
||||||
optional string protocol = 1;
|
optional string protocol = 1;
|
||||||
|
@ -136,7 +136,7 @@ type NetworkPolicyEgressRule struct {
|
|||||||
|
|
||||||
// NetworkPolicyPort describes a port to allow traffic on
|
// NetworkPolicyPort describes a port to allow traffic on
|
||||||
type NetworkPolicyPort struct {
|
type NetworkPolicyPort struct {
|
||||||
// The protocol (TCP or UDP) which traffic must match. If not specified, this
|
// The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this
|
||||||
// field defaults to TCP.
|
// field defaults to TCP.
|
||||||
// +optional
|
// +optional
|
||||||
Protocol *v1.Protocol `json:"protocol,omitempty" protobuf:"bytes,1,opt,name=protocol,casttype=k8s.io/api/core/v1.Protocol"`
|
Protocol *v1.Protocol `json:"protocol,omitempty" protobuf:"bytes,1,opt,name=protocol,casttype=k8s.io/api/core/v1.Protocol"`
|
||||||
|
@ -90,7 +90,7 @@ func (NetworkPolicyPeer) SwaggerDoc() map[string]string {
|
|||||||
|
|
||||||
var map_NetworkPolicyPort = map[string]string{
|
var map_NetworkPolicyPort = map[string]string{
|
||||||
"": "NetworkPolicyPort describes a port to allow traffic on",
|
"": "NetworkPolicyPort describes a port to allow traffic on",
|
||||||
"protocol": "The protocol (TCP or UDP) which traffic must match. If not specified, this field defaults to TCP.",
|
"protocol": "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.",
|
||||||
"port": "The port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers.",
|
"port": "The port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user