mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
vendor updates
This commit is contained in:
32
vendor/k8s.io/kubernetes/pkg/proxy/BUILD
generated
vendored
32
vendor/k8s.io/kubernetes/pkg/proxy/BUILD
generated
vendored
@ -3,16 +3,29 @@ package(default_visibility = ["//visibility:public"])
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"endpoints.go",
|
||||
"service.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy",
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/types:go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/util/net:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
@ -39,3 +52,20 @@ filegroup(
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"endpoints_test.go",
|
||||
"service_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/proxy/OWNERS
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/proxy/OWNERS
generated
vendored
@ -11,3 +11,4 @@ reviewers:
|
||||
- freehan
|
||||
- dcbw
|
||||
- m1093782566
|
||||
- danwinship
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/BUILD
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/BUILD
generated
vendored
@ -32,6 +32,7 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/fuzzer:all-srcs",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/scheme:all-srcs",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:all-srcs",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/validation:all-srcs",
|
||||
|
29
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer/BUILD
generated
vendored
Normal file
29
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer/BUILD
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/proxy/apis/kubeproxyconfig:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
52
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer/fuzzer.go
generated
vendored
Normal file
52
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer/fuzzer.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fuzzer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
)
|
||||
|
||||
// Funcs returns the fuzzer functions for the kube-proxy apis.
|
||||
func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(obj *kubeproxyconfig.KubeProxyConfiguration, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj)
|
||||
obj.BindAddress = fmt.Sprintf("%d.%d.%d.%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256))
|
||||
obj.ClientConnection.ContentType = c.RandString()
|
||||
obj.Conntrack.MaxPerCore = utilpointer.Int32Ptr(c.Int31())
|
||||
obj.Conntrack.Min = utilpointer.Int32Ptr(c.Int31())
|
||||
obj.Conntrack.TCPCloseWaitTimeout = &metav1.Duration{Duration: time.Duration(c.Int63()) * time.Hour}
|
||||
obj.Conntrack.TCPEstablishedTimeout = &metav1.Duration{Duration: time.Duration(c.Int63()) * time.Hour}
|
||||
obj.FeatureGates = map[string]bool{c.RandString(): true}
|
||||
obj.HealthzBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536))
|
||||
obj.IPTables.MasqueradeBit = utilpointer.Int32Ptr(c.Int31())
|
||||
obj.MetricsBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536))
|
||||
obj.OOMScoreAdj = utilpointer.Int32Ptr(c.Int31())
|
||||
obj.ResourceContainer = "foo"
|
||||
obj.ClientConnection.ContentType = "bar"
|
||||
obj.NodePortAddresses = []string{"1.2.3.0/24"}
|
||||
},
|
||||
}
|
||||
}
|
12
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme/BUILD
generated
vendored
12
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme/BUILD
generated
vendored
@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@ -26,3 +26,13 @@ filegroup(
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["scheme_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/proxy/apis/kubeproxyconfig/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
|
||||
],
|
||||
)
|
||||
|
28
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme/scheme_test.go
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme/scheme_test.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/fuzzer"
|
||||
)
|
||||
|
||||
func TestRoundTripTypes(t *testing.T) {
|
||||
roundtrip.RoundTripTestForScheme(t, Scheme, fuzzer.Funcs)
|
||||
}
|
38
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/types.go
generated
vendored
38
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/types.go
generated
vendored
@ -26,7 +26,7 @@ import (
|
||||
|
||||
// ClientConnectionConfiguration contains details for constructing a client.
|
||||
type ClientConnectionConfiguration struct {
|
||||
// kubeConfigFile is the path to a kubeconfig file.
|
||||
// kubeconfig is the path to a kubeconfig file.
|
||||
KubeConfigFile string
|
||||
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
|
||||
// default value of 'application/json'. This field will control all connections to the server used by a particular
|
||||
@ -97,14 +97,8 @@ type KubeProxyConntrackConfiguration struct {
|
||||
type KubeProxyConfiguration struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// featureGates is a comma-separated list of key=value pairs that control
|
||||
// which alpha/beta features are enabled.
|
||||
//
|
||||
// TODO this really should be a map but that requires refactoring all
|
||||
// components to use config files because local-up-cluster.sh only supports
|
||||
// the --feature-gates flag right now, which is comma-separated key=value
|
||||
// pairs.
|
||||
FeatureGates string
|
||||
// featureGates is a map of feature names to bools that enable or disable alpha/experimental features.
|
||||
FeatureGates map[string]bool
|
||||
|
||||
// bindAddress is the IP address for the proxy server to serve on (set to 0.0.0.0
|
||||
// for all interfaces)
|
||||
@ -150,15 +144,29 @@ type KubeProxyConfiguration struct {
|
||||
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
||||
// than 0.
|
||||
ConfigSyncPeriod metav1.Duration
|
||||
// nodePortAddresses is the --nodeport-addresses value for kube-proxy process. Values must be valid
|
||||
// IP blocks. These values are as a parameter to select the interfaces where nodeport works.
|
||||
// In case someone would like to expose a service on localhost for local visit and some other interfaces for
|
||||
// particular purpose, a list of IP blocks would do that.
|
||||
// If set it to "127.0.0.0/8", kube-proxy will only select the loopback interface for NodePort.
|
||||
// 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.
|
||||
NodePortAddresses []string
|
||||
}
|
||||
|
||||
// Currently, four modes of proxying are available total: 'userspace' (older, stable), 'iptables'
|
||||
// (newer, faster), 'ipvs', and 'kernelspace' (Windows only, newer).
|
||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||
// (newer, faster), 'ipvs'(newest, better in performance and scalability).
|
||||
//
|
||||
// If blank, use the best-available proxy (currently iptables, but may change in
|
||||
// future versions). If the iptables proxy is selected, regardless of how, but
|
||||
// the system's kernel or iptables versions are insufficient, this always falls
|
||||
// back to the userspace proxy.
|
||||
// Two modes of proxy are available in Windows platform: 'userspace'(older, stable) and 'kernelspace' (newer, faster).
|
||||
//
|
||||
// In Linux platform, if proxy mode is blank, use the best-available proxy (currently iptables, but may change in the
|
||||
// future). If the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are
|
||||
// insufficient, this always falls back to the userspace proxy. IPVS mode will be enabled when proxy mode is set to 'ipvs',
|
||||
// and the fall back path is firstly iptables and then userspace.
|
||||
|
||||
// In Windows platform, if proxy mode is blank, use the best-available proxy (currently userspace, but may change in the
|
||||
// future). If winkernel proxy is selected, regardless of how, but the Windows kernel can't support this mode of proxy,
|
||||
// this always falls back to the userspace proxy.
|
||||
type ProxyMode string
|
||||
|
||||
const (
|
||||
|
3
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1/defaults.go
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1/defaults.go
generated
vendored
@ -116,4 +116,7 @@ func SetDefaults_KubeProxyConfiguration(obj *KubeProxyConfiguration) {
|
||||
if obj.ClientConnection.Burst == 0 {
|
||||
obj.ClientConnection.Burst = 10
|
||||
}
|
||||
if obj.FeatureGates == nil {
|
||||
obj.FeatureGates = make(map[string]bool)
|
||||
}
|
||||
}
|
||||
|
47
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1/types.go
generated
vendored
47
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1/types.go
generated
vendored
@ -22,7 +22,7 @@ import (
|
||||
|
||||
// ClientConnectionConfiguration contains details for constructing a client.
|
||||
type ClientConnectionConfiguration struct {
|
||||
// kubeConfigFile is the path to a kubeconfig file.
|
||||
// kubeconfig is the path to a kubeconfig file.
|
||||
KubeConfigFile string `json:"kubeconfig"`
|
||||
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
|
||||
// default value of 'application/json'. This field will control all connections to the server used by a particular
|
||||
@ -30,7 +30,7 @@ type ClientConnectionConfiguration struct {
|
||||
AcceptContentTypes string `json:"acceptContentTypes"`
|
||||
// contentType is the content type used when sending data to the server from this client.
|
||||
ContentType string `json:"contentType"`
|
||||
// cps controls the number of queries per second allowed for this connection.
|
||||
// qps controls the number of queries per second allowed for this connection.
|
||||
QPS float32 `json:"qps"`
|
||||
// burst allows extra queries to accumulate when a client is exceeding its rate.
|
||||
Burst int `json:"burst"`
|
||||
@ -93,14 +93,8 @@ type KubeProxyConntrackConfiguration struct {
|
||||
type KubeProxyConfiguration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// featureGates is a comma-separated list of key=value pairs that control
|
||||
// which alpha/beta features are enabled.
|
||||
//
|
||||
// TODO this really should be a map but that requires refactoring all
|
||||
// components to use config files because local-up-cluster.sh only supports
|
||||
// the --feature-gates flag right now, which is comma-separated key=value
|
||||
// pairs.
|
||||
FeatureGates string `json:"featureGates"`
|
||||
// featureGates is a map of feature names to bools that enable or disable alpha/experimental features.
|
||||
FeatureGates map[string]bool `json:"featureGates,omitempty"`
|
||||
|
||||
// bindAddress is the IP address for the proxy server to serve on (set to 0.0.0.0
|
||||
// for all interfaces)
|
||||
@ -140,22 +134,33 @@ type KubeProxyConfiguration struct {
|
||||
ResourceContainer string `json:"resourceContainer"`
|
||||
// udpIdleTimeout is how long an idle UDP connection will be kept open (e.g. '250ms', '2s').
|
||||
// Must be greater than 0. Only applicable for proxyMode=userspace.
|
||||
UDPIdleTimeout metav1.Duration `json:"udpTimeoutMilliseconds"`
|
||||
UDPIdleTimeout metav1.Duration `json:"udpIdleTimeout"`
|
||||
// conntrack contains conntrack-related configuration options.
|
||||
Conntrack KubeProxyConntrackConfiguration `json:"conntrack"`
|
||||
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
||||
// than 0.
|
||||
ConfigSyncPeriod metav1.Duration `json:"configSyncPeriod"`
|
||||
// nodePortAddresses is the --nodeport-addresses value for kube-proxy process. Values must be valid
|
||||
// IP blocks. These values are as a parameter to select the interfaces where nodeport works.
|
||||
// In case someone would like to expose a service on localhost for local visit and some other interfaces for
|
||||
// particular purpose, a list of IP blocks would do that.
|
||||
// If set it to "127.0.0.0/8", kube-proxy will only select the loopback interface for NodePort.
|
||||
// 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.
|
||||
NodePortAddresses []string `json:"nodePortAddresses"`
|
||||
}
|
||||
|
||||
// Currently two modes of proxying are available: 'userspace' (older, stable) or 'iptables'
|
||||
// (newer, faster). If blank, use the best-available proxy (currently iptables, but may
|
||||
// change in future versions). If the iptables proxy is selected, regardless of how, but
|
||||
// the system's kernel or iptables versions are insufficient, this always falls back to the
|
||||
// userspace proxy.
|
||||
type ProxyMode string
|
||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||
// (newer, faster), 'ipvs'(newest, better in performance and scalability).
|
||||
//
|
||||
// Two modes of proxy are available in Windows platform: 'userspace'(older, stable) and 'kernelspace' (newer, faster).
|
||||
//
|
||||
// In Linux platform, if proxy mode is blank, use the best-available proxy (currently iptables, but may change in the
|
||||
// future). If the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are
|
||||
// insufficient, this always falls back to the userspace proxy. IPVS mode will be enabled when proxy mode is set to 'ipvs',
|
||||
// and the fall back path is firstly iptables and then userspace.
|
||||
|
||||
const (
|
||||
ProxyModeUserspace ProxyMode = "userspace"
|
||||
ProxyModeIPTables ProxyMode = "iptables"
|
||||
)
|
||||
// In Windows platform, if proxy mode is blank, use the best-available proxy (currently userspace, but may change in the
|
||||
// future). If winkernel proxy is selected, regardless of how, but the Windows kernel can't support this mode of proxy,
|
||||
// this always falls back to the userspace proxy.
|
||||
type ProxyMode string
|
||||
|
@ -16,16 +16,17 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
// Code generated by conversion-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
unsafe "unsafe"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -78,7 +79,7 @@ func Convert_kubeproxyconfig_ClientConnectionConfiguration_To_v1alpha1_ClientCon
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeProxyConfiguration_To_kubeproxyconfig_KubeProxyConfiguration(in *KubeProxyConfiguration, out *kubeproxyconfig.KubeProxyConfiguration, s conversion.Scope) error {
|
||||
out.FeatureGates = in.FeatureGates
|
||||
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
||||
out.BindAddress = in.BindAddress
|
||||
out.HealthzBindAddress = in.HealthzBindAddress
|
||||
out.MetricsBindAddress = in.MetricsBindAddress
|
||||
@ -103,6 +104,7 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_kubeproxyconfig_KubeProxyCon
|
||||
return err
|
||||
}
|
||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -112,7 +114,7 @@ func Convert_v1alpha1_KubeProxyConfiguration_To_kubeproxyconfig_KubeProxyConfigu
|
||||
}
|
||||
|
||||
func autoConvert_kubeproxyconfig_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguration(in *kubeproxyconfig.KubeProxyConfiguration, out *KubeProxyConfiguration, s conversion.Scope) error {
|
||||
out.FeatureGates = in.FeatureGates
|
||||
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
||||
out.BindAddress = in.BindAddress
|
||||
out.HealthzBindAddress = in.HealthzBindAddress
|
||||
out.MetricsBindAddress = in.MetricsBindAddress
|
||||
@ -137,6 +139,7 @@ func autoConvert_kubeproxyconfig_KubeProxyConfiguration_To_v1alpha1_KubeProxyCon
|
||||
return err
|
||||
}
|
||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
@ -45,6 +45,13 @@ func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfigurati
|
||||
func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.FeatureGates != nil {
|
||||
in, out := &in.FeatureGates, &out.FeatureGates
|
||||
*out = make(map[string]bool, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.ClientConnection = in.ClientConnection
|
||||
in.IPTables.DeepCopyInto(&out.IPTables)
|
||||
out.IPVS = in.IPVS
|
||||
@ -60,6 +67,11 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
||||
out.UDPIdleTimeout = in.UDPIdleTimeout
|
||||
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||
if in.NodePortAddresses != nil {
|
||||
in, out := &in.NodePortAddresses, &out.NodePortAddresses
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -77,9 +89,8 @@ func (in *KubeProxyConfiguration) DeepCopy() *KubeProxyConfiguration {
|
||||
func (in *KubeProxyConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
|
@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by defaulter-gen. Do not edit it manually!
|
||||
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
|
4
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/BUILD
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/BUILD
generated
vendored
@ -14,6 +14,7 @@ go_library(
|
||||
"//pkg/apis/core/validation:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
@ -34,8 +35,7 @@ filegroup(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["validation_test.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/proxy/apis/kubeproxyconfig:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
|
59
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/validation.go
generated
vendored
59
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/validation.go
generated
vendored
@ -24,6 +24,7 @@ import (
|
||||
"strings"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
@ -36,7 +37,9 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList {
|
||||
newPath := field.NewPath("KubeProxyConfiguration")
|
||||
|
||||
allErrs = append(allErrs, validateKubeProxyIPTablesConfiguration(config.IPTables, newPath.Child("KubeProxyIPTablesConfiguration"))...)
|
||||
allErrs = append(allErrs, validateKubeProxyIPVSConfiguration(config.IPVS, newPath.Child("KubeProxyIPVSConfiguration"))...)
|
||||
if config.Mode == kubeproxyconfig.ProxyModeIPVS {
|
||||
allErrs = append(allErrs, validateKubeProxyIPVSConfiguration(config.IPVS, newPath.Child("KubeProxyIPVSConfiguration"))...)
|
||||
}
|
||||
allErrs = append(allErrs, validateKubeProxyConntrackConfiguration(config.Conntrack, newPath.Child("KubeProxyConntrackConfiguration"))...)
|
||||
allErrs = append(allErrs, validateProxyMode(config.Mode, newPath.Child("Mode"))...)
|
||||
allErrs = append(allErrs, validateClientConnectionConfiguration(config.ClientConnection, newPath.Child("ClientConnection"))...)
|
||||
@ -70,6 +73,8 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)"))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateKubeProxyNodePortAddress(config.NodePortAddresses, newPath.Child("NodePortAddresses"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@ -150,33 +155,32 @@ func validateProxyMode(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) fiel
|
||||
}
|
||||
|
||||
func validateProxyModeLinux(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
validModes := sets.NewString(
|
||||
string(kubeproxyconfig.ProxyModeUserspace),
|
||||
string(kubeproxyconfig.ProxyModeIPTables),
|
||||
string(kubeproxyconfig.ProxyModeIPVS),
|
||||
)
|
||||
|
||||
switch mode {
|
||||
case kubeproxyconfig.ProxyModeUserspace:
|
||||
case kubeproxyconfig.ProxyModeIPTables:
|
||||
case kubeproxyconfig.ProxyModeIPVS:
|
||||
case "":
|
||||
default:
|
||||
modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeIPTables), string(kubeproxyconfig.ProxyModeIPVS)}
|
||||
errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy [currently iptables])", strings.Join(modes, ","))
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg))
|
||||
if mode == "" || validModes.Has(string(mode)) {
|
||||
return nil
|
||||
}
|
||||
return allErrs
|
||||
|
||||
errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy [currently iptables])", strings.Join(validModes.List(), ","))
|
||||
return field.ErrorList{field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)}
|
||||
}
|
||||
|
||||
func validateProxyModeWindows(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
validModes := sets.NewString(
|
||||
string(kubeproxyconfig.ProxyModeUserspace),
|
||||
string(kubeproxyconfig.ProxyModeKernelspace),
|
||||
)
|
||||
|
||||
switch mode {
|
||||
case kubeproxyconfig.ProxyModeUserspace:
|
||||
case kubeproxyconfig.ProxyModeKernelspace:
|
||||
default:
|
||||
modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeKernelspace)}
|
||||
errMsg := fmt.Sprintf("must be %s or blank (blank means the most-available proxy [currently userspace])", strings.Join(modes, ","))
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg))
|
||||
if mode == "" || validModes.Has(string(mode)) {
|
||||
return nil
|
||||
}
|
||||
return allErrs
|
||||
|
||||
errMsg := fmt.Sprintf("must be %s or blank (blank means the most-available proxy [currently userspace])", strings.Join(validModes.List(), ","))
|
||||
return field.ErrorList{field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)}
|
||||
}
|
||||
|
||||
func validateClientConnectionConfiguration(config kubeproxyconfig.ClientConnectionConfiguration, fldPath *field.Path) field.ErrorList {
|
||||
@ -236,3 +240,16 @@ func validateIPVSSchedulerMethod(scheduler kubeproxyconfig.IPVSSchedulerMethod,
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKubeProxyNodePortAddress(nodePortAddresses []string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
for i := range nodePortAddresses {
|
||||
if _, _, err := net.ParseCIDR(nodePortAddresses[i]); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, nodePortAddresses, "must be a valid IP block"))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
144
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go
generated
vendored
144
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go
generated
vendored
@ -30,6 +30,12 @@ import (
|
||||
)
|
||||
|
||||
func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
var proxyMode kubeproxyconfig.ProxyMode
|
||||
if runtime.GOOS == "windows" {
|
||||
proxyMode = kubeproxyconfig.ProxyModeKernelspace
|
||||
} else {
|
||||
proxyMode = kubeproxyconfig.ProxyModeIPVS
|
||||
}
|
||||
successCases := []kubeproxyconfig.KubeProxyConfiguration{
|
||||
{
|
||||
BindAddress: "192.168.59.103",
|
||||
@ -43,6 +49,7 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Mode: proxyMode,
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
@ -55,6 +62,26 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
Min: pointer.Int32Ptr(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, successCase := range successCases {
|
||||
@ -81,10 +108,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -109,10 +132,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -137,10 +156,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -165,10 +180,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -193,10 +204,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -221,10 +228,31 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
Min: pointer.Int32Ptr(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||
BindAddress: "192.168.59.103",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
ClusterCIDR: "192.168.59.0/24",
|
||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
// not specifying valid period in IPVS mode.
|
||||
Mode: kubeproxyconfig.ProxyModeIPVS,
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
@ -651,3 +679,73 @@ func TestValidateIPVSSchedulerMethod(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateKubeProxyNodePortAddress(t *testing.T) {
|
||||
newPath := field.NewPath("KubeProxyConfiguration")
|
||||
|
||||
successCases := []struct {
|
||||
addresses []string
|
||||
}{
|
||||
{[]string{}},
|
||||
{[]string{"127.0.0.0/8"}},
|
||||
{[]string{"0.0.0.0/0"}},
|
||||
{[]string{"::/0"}},
|
||||
{[]string{"127.0.0.1/32", "1.2.3.0/24"}},
|
||||
{[]string{"127.0.0.0/8"}},
|
||||
{[]string{"127.0.0.1/32"}},
|
||||
{[]string{"::1/128"}},
|
||||
{[]string{"1.2.3.4/32"}},
|
||||
{[]string{"10.20.30.0/24"}},
|
||||
{[]string{"10.20.0.0/16", "100.200.0.0/16"}},
|
||||
{[]string{"10.0.0.0/8"}},
|
||||
{[]string{"2001:db8::/32"}},
|
||||
}
|
||||
|
||||
for _, successCase := range successCases {
|
||||
if errs := validateKubeProxyNodePortAddress(successCase.addresses, newPath.Child("NodePortAddresses")); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
errorCases := []struct {
|
||||
addresses []string
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
addresses: []string{"foo"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{"1.2.3"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{""},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{"10.20.30.40"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{"::1"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{"2001:db8:1"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
{
|
||||
addresses: []string{"2001:db8:xyz/64"},
|
||||
msg: "must be a valid IP block",
|
||||
},
|
||||
}
|
||||
|
||||
for _, errorCase := range errorCases {
|
||||
if errs := validateKubeProxyNodePortAddress(errorCase.addresses, newPath.Child("NodePortAddresses")); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", errorCase.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/zz_generated.deepcopy.go
generated
vendored
39
vendor/k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/zz_generated.deepcopy.go
generated
vendored
@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package kubeproxyconfig
|
||||
|
||||
@ -41,10 +41,39 @@ func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfigurati
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in ConfigurationMap) DeepCopyInto(out *ConfigurationMap) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(ConfigurationMap, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationMap.
|
||||
func (in ConfigurationMap) DeepCopy() ConfigurationMap {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConfigurationMap)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.FeatureGates != nil {
|
||||
in, out := &in.FeatureGates, &out.FeatureGates
|
||||
*out = make(map[string]bool, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.ClientConnection = in.ClientConnection
|
||||
in.IPTables.DeepCopyInto(&out.IPTables)
|
||||
out.IPVS = in.IPVS
|
||||
@ -60,6 +89,11 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
||||
out.UDPIdleTimeout = in.UDPIdleTimeout
|
||||
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||
if in.NodePortAddresses != nil {
|
||||
in, out := &in.NodePortAddresses, &out.NodePortAddresses
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -77,9 +111,8 @@ func (in *KubeProxyConfiguration) DeepCopy() *KubeProxyConfiguration {
|
||||
func (in *KubeProxyConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
|
3
vendor/k8s.io/kubernetes/pkg/proxy/config/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/proxy/config/BUILD
generated
vendored
@ -30,8 +30,7 @@ go_test(
|
||||
"api_test.go",
|
||||
"config_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/config",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
|
314
vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go
generated
vendored
Normal file
314
vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/record"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
)
|
||||
|
||||
// BaseEndpointInfo contains base information that defines an endpoint.
|
||||
// This could be used directly by proxier while processing endpoints,
|
||||
// or can be used for constructing a more specific EndpointInfo struct
|
||||
// defined by the proxier if needed.
|
||||
type BaseEndpointInfo struct {
|
||||
Endpoint string // TODO: should be an endpointString type
|
||||
// IsLocal indicates whether the endpoint is running in same host as kube-proxy.
|
||||
IsLocal bool
|
||||
}
|
||||
|
||||
var _ Endpoint = &BaseEndpointInfo{}
|
||||
|
||||
// String is part of proxy.Endpoint interface.
|
||||
func (info *BaseEndpointInfo) String() string {
|
||||
return info.Endpoint
|
||||
}
|
||||
|
||||
// GetIsLocal is part of proxy.Endpoint interface.
|
||||
func (info *BaseEndpointInfo) GetIsLocal() bool {
|
||||
return info.IsLocal
|
||||
}
|
||||
|
||||
// IP returns just the IP part of the endpoint, it's a part of proxy.Endpoint interface.
|
||||
func (info *BaseEndpointInfo) IP() string {
|
||||
return utilproxy.IPPart(info.Endpoint)
|
||||
}
|
||||
|
||||
// Port returns just the Port part of the endpoint.
|
||||
func (info *BaseEndpointInfo) Port() (int, error) {
|
||||
return utilproxy.PortPart(info.Endpoint)
|
||||
}
|
||||
|
||||
// Equal is part of proxy.Endpoint interface.
|
||||
func (info *BaseEndpointInfo) Equal(other Endpoint) bool {
|
||||
return info.String() == other.String() && info.GetIsLocal() == other.GetIsLocal()
|
||||
}
|
||||
|
||||
func newBaseEndpointInfo(IP string, port int, isLocal bool) *BaseEndpointInfo {
|
||||
return &BaseEndpointInfo{
|
||||
Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)),
|
||||
IsLocal: isLocal,
|
||||
}
|
||||
}
|
||||
|
||||
type makeEndpointFunc func(info *BaseEndpointInfo) Endpoint
|
||||
|
||||
// EndpointChangeTracker carries state about uncommitted changes to an arbitrary number of
|
||||
// Endpoints, keyed by their namespace and name.
|
||||
type EndpointChangeTracker struct {
|
||||
// lock protects items.
|
||||
lock sync.Mutex
|
||||
// hostname is the host where kube-proxy is running.
|
||||
hostname string
|
||||
// items maps a service to is endpointsChange.
|
||||
items map[types.NamespacedName]*endpointsChange
|
||||
// makeEndpointInfo allows proxier to inject customized information when processing endpoint.
|
||||
makeEndpointInfo makeEndpointFunc
|
||||
// isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable.
|
||||
isIPv6Mode *bool
|
||||
recorder record.EventRecorder
|
||||
}
|
||||
|
||||
// NewEndpointChangeTracker initializes an EndpointsChangeMap
|
||||
func NewEndpointChangeTracker(hostname string, makeEndpointInfo makeEndpointFunc, isIPv6Mode *bool, recorder record.EventRecorder) *EndpointChangeTracker {
|
||||
return &EndpointChangeTracker{
|
||||
hostname: hostname,
|
||||
items: make(map[types.NamespacedName]*endpointsChange),
|
||||
makeEndpointInfo: makeEndpointInfo,
|
||||
isIPv6Mode: isIPv6Mode,
|
||||
recorder: recorder,
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates given service's endpoints change map based on the <previous, current> endpoints pair. It returns true
|
||||
// if items changed, otherwise return false. Update can be used to add/update/delete items of EndpointsChangeMap. For example,
|
||||
// Add item
|
||||
// - pass <nil, endpoints> as the <previous, current> pair.
|
||||
// Update item
|
||||
// - pass <oldEndpoints, endpoints> as the <previous, current> pair.
|
||||
// Delete item
|
||||
// - pass <endpoints, nil> as the <previous, current> pair.
|
||||
func (ect *EndpointChangeTracker) Update(previous, current *api.Endpoints) bool {
|
||||
endpoints := current
|
||||
if endpoints == nil {
|
||||
endpoints = previous
|
||||
}
|
||||
// previous == nil && current == nil is unexpected, we should return false directly.
|
||||
if endpoints == nil {
|
||||
return false
|
||||
}
|
||||
namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name}
|
||||
|
||||
ect.lock.Lock()
|
||||
defer ect.lock.Unlock()
|
||||
|
||||
change, exists := ect.items[namespacedName]
|
||||
if !exists {
|
||||
change = &endpointsChange{}
|
||||
change.previous = ect.endpointsToEndpointsMap(previous)
|
||||
ect.items[namespacedName] = change
|
||||
}
|
||||
change.current = ect.endpointsToEndpointsMap(current)
|
||||
// if change.previous equal to change.current, it means no change
|
||||
if reflect.DeepEqual(change.previous, change.current) {
|
||||
delete(ect.items, namespacedName)
|
||||
}
|
||||
return len(ect.items) > 0
|
||||
}
|
||||
|
||||
// endpointsChange contains all changes to endpoints that happened since proxy rules were synced. For a single object,
|
||||
// changes are accumulated, i.e. previous is state from before applying the changes,
|
||||
// current is state after applying the changes.
|
||||
type endpointsChange struct {
|
||||
previous EndpointsMap
|
||||
current EndpointsMap
|
||||
}
|
||||
|
||||
// UpdateEndpointMapResult is the updated results after applying endpoints changes.
|
||||
type UpdateEndpointMapResult struct {
|
||||
// HCEndpointsLocalIPSize maps an endpoints name to the length of its local IPs.
|
||||
HCEndpointsLocalIPSize map[types.NamespacedName]int
|
||||
// StaleEndpoints identifies if an endpoints service pair is stale.
|
||||
StaleEndpoints []ServiceEndpoint
|
||||
// StaleServiceNames identifies if a service is stale.
|
||||
StaleServiceNames []ServicePortName
|
||||
}
|
||||
|
||||
// UpdateEndpointsMap updates endpointsMap base on the given changes.
|
||||
func UpdateEndpointsMap(endpointsMap EndpointsMap, changes *EndpointChangeTracker) (result UpdateEndpointMapResult) {
|
||||
result.StaleEndpoints = make([]ServiceEndpoint, 0)
|
||||
result.StaleServiceNames = make([]ServicePortName, 0)
|
||||
|
||||
endpointsMap.apply(changes, &result.StaleEndpoints, &result.StaleServiceNames)
|
||||
|
||||
// TODO: If this will appear to be computationally expensive, consider
|
||||
// computing this incrementally similarly to endpointsMap.
|
||||
result.HCEndpointsLocalIPSize = make(map[types.NamespacedName]int)
|
||||
localIPs := GetLocalEndpointIPs(endpointsMap)
|
||||
for nsn, ips := range localIPs {
|
||||
result.HCEndpointsLocalIPSize[nsn] = len(ips)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// EndpointsMap maps a service name to a list of all its Endpoints.
|
||||
type EndpointsMap map[ServicePortName][]Endpoint
|
||||
|
||||
// endpointsToEndpointsMap translates single Endpoints object to EndpointsMap.
|
||||
// This function is used for incremental updated of endpointsMap.
|
||||
//
|
||||
// NOTE: endpoints object should NOT be modified.
|
||||
func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *api.Endpoints) EndpointsMap {
|
||||
if endpoints == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
endpointsMap := make(EndpointsMap)
|
||||
// We need to build a map of portname -> all ip:ports for that
|
||||
// portname. Explode Endpoints.Subsets[*] into this structure.
|
||||
for i := range endpoints.Subsets {
|
||||
ss := &endpoints.Subsets[i]
|
||||
for i := range ss.Ports {
|
||||
port := &ss.Ports[i]
|
||||
if port.Port == 0 {
|
||||
glog.Warningf("ignoring invalid endpoint port %s", port.Name)
|
||||
continue
|
||||
}
|
||||
svcPortName := ServicePortName{
|
||||
NamespacedName: types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name},
|
||||
Port: port.Name,
|
||||
}
|
||||
for i := range ss.Addresses {
|
||||
addr := &ss.Addresses[i]
|
||||
if addr.IP == "" {
|
||||
glog.Warningf("ignoring invalid endpoint port %s with empty host", port.Name)
|
||||
continue
|
||||
}
|
||||
// Filter out the incorrect IP version case.
|
||||
// Any endpoint port that contains incorrect IP version will be ignored.
|
||||
if ect.isIPv6Mode != nil && utilnet.IsIPv6String(addr.IP) != *ect.isIPv6Mode {
|
||||
// Emit event on the corresponding service which had a different
|
||||
// IP version than the endpoint.
|
||||
utilproxy.LogAndEmitIncorrectIPVersionEvent(ect.recorder, "endpoints", addr.IP, endpoints.Name, endpoints.Namespace, "")
|
||||
continue
|
||||
}
|
||||
isLocal := addr.NodeName != nil && *addr.NodeName == ect.hostname
|
||||
baseEndpointInfo := newBaseEndpointInfo(addr.IP, int(port.Port), isLocal)
|
||||
if ect.makeEndpointInfo != nil {
|
||||
endpointsMap[svcPortName] = append(endpointsMap[svcPortName], ect.makeEndpointInfo(baseEndpointInfo))
|
||||
} else {
|
||||
endpointsMap[svcPortName] = append(endpointsMap[svcPortName], baseEndpointInfo)
|
||||
}
|
||||
}
|
||||
if glog.V(3) {
|
||||
newEPList := []string{}
|
||||
for _, ep := range endpointsMap[svcPortName] {
|
||||
newEPList = append(newEPList, ep.String())
|
||||
}
|
||||
glog.Infof("Setting endpoints for %q to %+v", svcPortName, newEPList)
|
||||
}
|
||||
}
|
||||
}
|
||||
return endpointsMap
|
||||
}
|
||||
|
||||
// apply the changes to EndpointsMap and updates stale endpoints and service-endpoints pair. The `staleEndpoints` argument
|
||||
// is passed in to store the stale udp endpoints and `staleServiceNames` argument is passed in to store the stale udp service.
|
||||
// The changes map is cleared after applying them.
|
||||
func (endpointsMap EndpointsMap) apply(changes *EndpointChangeTracker, staleEndpoints *[]ServiceEndpoint, staleServiceNames *[]ServicePortName) {
|
||||
if changes == nil {
|
||||
return
|
||||
}
|
||||
changes.lock.Lock()
|
||||
defer changes.lock.Unlock()
|
||||
for _, change := range changes.items {
|
||||
endpointsMap.Unmerge(change.previous)
|
||||
endpointsMap.Merge(change.current)
|
||||
detectStaleConnections(change.previous, change.current, staleEndpoints, staleServiceNames)
|
||||
}
|
||||
changes.items = make(map[types.NamespacedName]*endpointsChange)
|
||||
}
|
||||
|
||||
// Merge ensures that the current EndpointsMap contains all <service, endpoints> pairs from the EndpointsMap passed in.
|
||||
func (em EndpointsMap) Merge(other EndpointsMap) {
|
||||
for svcPortName := range other {
|
||||
em[svcPortName] = other[svcPortName]
|
||||
}
|
||||
}
|
||||
|
||||
// Unmerge removes the <service, endpoints> pairs from the current EndpointsMap which are contained in the EndpointsMap passed in.
|
||||
func (em EndpointsMap) Unmerge(other EndpointsMap) {
|
||||
for svcPortName := range other {
|
||||
delete(em, svcPortName)
|
||||
}
|
||||
}
|
||||
|
||||
// GetLocalEndpointIPs returns endpoints IPs if given endpoint is local - local means the endpoint is running in same host as kube-proxy.
|
||||
func GetLocalEndpointIPs(endpointsMap EndpointsMap) map[types.NamespacedName]sets.String {
|
||||
localIPs := make(map[types.NamespacedName]sets.String)
|
||||
for svcPortName, epList := range endpointsMap {
|
||||
for _, ep := range epList {
|
||||
if ep.GetIsLocal() {
|
||||
nsn := svcPortName.NamespacedName
|
||||
if localIPs[nsn] == nil {
|
||||
localIPs[nsn] = sets.NewString()
|
||||
}
|
||||
localIPs[nsn].Insert(ep.IP())
|
||||
}
|
||||
}
|
||||
}
|
||||
return localIPs
|
||||
}
|
||||
|
||||
// detectStaleConnections modifies <staleEndpoints> and <staleServices> with detected stale connections. <staleServiceNames>
|
||||
// is used to store stale udp service in order to clear udp conntrack later.
|
||||
func detectStaleConnections(oldEndpointsMap, newEndpointsMap EndpointsMap, staleEndpoints *[]ServiceEndpoint, staleServiceNames *[]ServicePortName) {
|
||||
for svcPortName, epList := range oldEndpointsMap {
|
||||
for _, ep := range epList {
|
||||
stale := true
|
||||
for i := range newEndpointsMap[svcPortName] {
|
||||
if newEndpointsMap[svcPortName][i].Equal(ep) {
|
||||
stale = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if stale {
|
||||
glog.V(4).Infof("Stale endpoint %v -> %v", svcPortName, ep.String())
|
||||
*staleEndpoints = append(*staleEndpoints, ServiceEndpoint{Endpoint: ep.String(), ServicePortName: svcPortName})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for svcPortName, epList := range newEndpointsMap {
|
||||
// For udp service, if its backend changes from 0 to non-0. There may exist a conntrack entry that could blackhole traffic to the service.
|
||||
if len(epList) > 0 && len(oldEndpointsMap[svcPortName]) == 0 {
|
||||
*staleServiceNames = append(*staleServiceNames, svcPortName)
|
||||
}
|
||||
}
|
||||
}
|
1291
vendor/k8s.io/kubernetes/pkg/proxy/endpoints_test.go
generated
vendored
Normal file
1291
vendor/k8s.io/kubernetes/pkg/proxy/endpoints_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/BUILD
generated
vendored
@ -28,8 +28,7 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["healthcheck_test.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/healthcheck",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/healthcheck.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/healthcheck.go
generated
vendored
@ -73,7 +73,7 @@ type HTTPServerFactory interface {
|
||||
|
||||
// HTTPServer allows for testing of Server.
|
||||
type HTTPServer interface {
|
||||
// Server is designed so that http.Server satifies this interface,
|
||||
// Server is designed so that http.Server satisfies this interface,
|
||||
Serve(listener net.Listener) error
|
||||
}
|
||||
|
||||
|
14
vendor/k8s.io/kubernetes/pkg/proxy/iptables/BUILD
generated
vendored
14
vendor/k8s.io/kubernetes/pkg/proxy/iptables/BUILD
generated
vendored
@ -13,24 +13,21 @@ go_library(
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/iptables",
|
||||
deps = [
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/healthcheck:go_default_library",
|
||||
"//pkg/proxy/metrics:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
"//pkg/util/conntrack:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/net:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
@ -39,21 +36,20 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["proxier_test.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/iptables",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/proxy/util/testing:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
"//pkg/util/conntrack:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/iptables/testing:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec/testing:go_default_library",
|
||||
],
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS
generated
vendored
@ -4,3 +4,4 @@ reviewers:
|
||||
- justinsb
|
||||
- freehan
|
||||
- dcbw
|
||||
- danwinship
|
||||
|
1092
vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go
generated
vendored
1092
vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go
generated
vendored
File diff suppressed because it is too large
Load Diff
719
vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go
generated
vendored
719
vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
48
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/BUILD
generated
vendored
48
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/BUILD
generated
vendored
@ -12,20 +12,19 @@ go_test(
|
||||
"ipset_test.go",
|
||||
"proxier_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/ipvs",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/ipvs/testing:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/proxy/util/testing:go_default_library",
|
||||
"//pkg/util/ipset:go_default_library",
|
||||
"//pkg/util/ipset/testing:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/iptables/testing:go_default_library",
|
||||
"//pkg/util/ipvs:go_default_library",
|
||||
"//pkg/util/ipvs/testing:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
@ -40,42 +39,69 @@ go_library(
|
||||
srcs = [
|
||||
"ipset.go",
|
||||
"netlink.go",
|
||||
"netlink_unsupported.go",
|
||||
"proxier.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"netlink_linux.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:nacl": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:plan9": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:solaris": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"netlink_unsupported.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/ipvs",
|
||||
deps = [
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/healthcheck:go_default_library",
|
||||
"//pkg/proxy/metrics:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
"//pkg/util/conntrack:go_default_library",
|
||||
"//pkg/util/ipset:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/ipvs:go_default_library",
|
||||
"//pkg/util/net:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/github.com/vishvananda/netlink:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
|
8
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/OWNERS
generated
vendored
Normal file
8
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/OWNERS
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- brendandburns
|
||||
- m1093782566
|
||||
approvers:
|
||||
- thockin
|
||||
- brendandburns
|
||||
- m1093782566
|
75
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/README.md
generated
vendored
75
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/README.md
generated
vendored
@ -8,60 +8,41 @@ This document shows how to use kube-proxy ipvs mode.
|
||||
Linux kernel.
|
||||
|
||||
IPVS runs on a host and acts as a load balancer in front of a cluster of real servers. IPVS can direct requests for TCP
|
||||
and UDP-based services to the real servers, and make services of real servers appear as irtual services on a single IP address.
|
||||
and UDP-based services to the real servers, and make services of real servers appear as virtual services on a single IP address.
|
||||
|
||||
## How to use
|
||||
## Run kube-proxy in ipvs mode
|
||||
|
||||
#### Load IPVS kernel modules
|
||||
Currently, local-up scripts and kubeadm support switching IPVS proxy mode via exporting environment variables or specifying flags.
|
||||
|
||||
Currently the IPVS kernel module can't be loaded automatically, so first we should use the following command to load IPVS kernel
|
||||
modules manually.
|
||||
|
||||
```shell
|
||||
modprobe ip_vs
|
||||
modprobe ip_vs_rr
|
||||
modprobe ip_vs_wrr
|
||||
modprobe ip_vs_sh
|
||||
modprobe nf_conntrack_ipv4
|
||||
```
|
||||
|
||||
After that, use `lsmod | grep ip_vs` to make sure kernel modules are loaded.
|
||||
|
||||
#### Run kube-proxy in ipvs mode
|
||||
|
||||
#### Local UP Cluster
|
||||
### Local UP Cluster
|
||||
|
||||
Kube-proxy will run in iptables mode by default in a [local-up cluster](https://github.com/kubernetes/community/blob/master/contributors/devel/running-locally.md).
|
||||
|
||||
Users should export the env `KUBEPROXY_MODE=ipvs` to specify the ipvs mode before deploying the cluster if want to run kube-proxy in ipvs mode.
|
||||
Users should export the env `KUBE_PROXY_MODE=ipvs` to specify the ipvs mode before deploying the cluster if want to run kube-proxy in ipvs mode.
|
||||
|
||||
#### Cluster Created by Kubeadm
|
||||
### Cluster Created by Kubeadm
|
||||
|
||||
Kube-proxy will run in iptables mode by default in a cluster deployed by [kubeadm](https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/).
|
||||
|
||||
Since IPVS mode is still feature-gated, users should add the flag `--feature-gates=SupportIPVSProxyMode=true` in `kubeadm init` command
|
||||
|
||||
```
|
||||
kubeadm init --feature-gates=SupportIPVSProxyMode=true
|
||||
```
|
||||
|
||||
to specify the ipvs mode before deploying the cluster if want to run kube-proxy in ipvs mode.
|
||||
|
||||
If you are using kubeadm with a configuration file, you can specify the ipvs mode adding `SupportIPVSProxyMode: true` below the `featureGates` field.
|
||||
If you are using kubeadm with a [configuration file](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file), you can specify the ipvs mode adding `SupportIPVSProxyMode: true` below the `kubeProxy` field.
|
||||
Then the configuration file is similar to:
|
||||
|
||||
```json
|
||||
kind: MasterConfiguration
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
...
|
||||
featureGates:
|
||||
SupportIPVSProxyMode: true
|
||||
kubeProxy:
|
||||
config:
|
||||
featureGates: SupportIPVSProxyMode=true
|
||||
mode: ipvs
|
||||
...
|
||||
```
|
||||
|
||||
#### Test
|
||||
## Debug
|
||||
|
||||
Use `ipvsadm` tool to test whether the kube-proxy start succeed. By default we may get result like:
|
||||
### Check IPVS proxy rules
|
||||
|
||||
People can use `ipvsadm` tool to check whether kube-proxy are maintaining IPVS rules correctly. For example, we may get IPVS proxy rules like:
|
||||
|
||||
```shell
|
||||
# ipvsadm -ln
|
||||
@ -73,3 +54,29 @@ TCP 10.0.0.1:443 rr persistent 10800
|
||||
TCP 10.0.0.10:53 rr
|
||||
UDP 10.0.0.10:53 rr
|
||||
```
|
||||
|
||||
### Why kube-proxy can't start IPVS mode
|
||||
|
||||
People can do the following check list step by step:
|
||||
|
||||
**1. Enable IPVS feature gateway**
|
||||
|
||||
Currently IPVS-based kube-proxy is still in alpha phase, people need to enable `--feature-gates=SupportIPVSProxyMode=true` explicitly.
|
||||
|
||||
**2. Specify proxy-mode=ipvs**
|
||||
|
||||
Tell kube-proxy that proxy-mode=ipvs, please.
|
||||
|
||||
**3. Load ipvs required kernel modules**
|
||||
|
||||
The following kernel modules are required by IPVS-based kube-proxy:
|
||||
|
||||
```shell
|
||||
ip_vs
|
||||
ip_vs_rr
|
||||
ip_vs_wrr
|
||||
ip_vs_sh
|
||||
nf_conntrack_ipv4
|
||||
```
|
||||
|
||||
IPVS-based kube-proxy will load them automatically. If it fails to load them, please check whether they are compiled into your kernel.
|
||||
|
10
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/ipset.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/ipset.go
generated
vendored
@ -89,6 +89,10 @@ func NewIPSet(handle utilipset.Interface, name string, setType utilipset.Type, i
|
||||
return set
|
||||
}
|
||||
|
||||
func (set *IPSet) validateEntry(entry *utilipset.Entry) bool {
|
||||
return entry.Validate(&set.IPSet)
|
||||
}
|
||||
|
||||
func (set *IPSet) isEmpty() bool {
|
||||
return len(set.activeEntries.UnsortedList()) == 0
|
||||
}
|
||||
@ -114,14 +118,16 @@ func (set *IPSet) syncIPSetEntries() {
|
||||
// Clean legacy entries
|
||||
for _, entry := range currentIPSetEntries.Difference(set.activeEntries).List() {
|
||||
if err := set.handle.DelEntry(entry, set.Name); err != nil {
|
||||
glog.Errorf("Failed to delete ip set entry: %s from ip set: %s, error: %v", entry, set.Name, err)
|
||||
if !utilipset.IsNotFoundError(err) {
|
||||
glog.Errorf("Failed to delete ip set entry: %s from ip set: %s, error: %v", entry, set.Name, err)
|
||||
}
|
||||
} else {
|
||||
glog.V(3).Infof("Successfully delete legacy ip set entry: %s from ip set: %s", entry, set.Name)
|
||||
}
|
||||
}
|
||||
// Create active entries
|
||||
for _, entry := range set.activeEntries.Difference(currentIPSetEntries).List() {
|
||||
if err := set.handle.AddEntry(entry, set.Name, true); err != nil {
|
||||
if err := set.handle.AddEntry(entry, &set.IPSet, true); err != nil {
|
||||
glog.Errorf("Failed to add entry: %v to ip set: %s, error: %v", entry, set.Name, err)
|
||||
} else {
|
||||
glog.V(3).Infof("Successfully add entry: %v to ip set: %s", entry, set.Name)
|
||||
|
157
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/ipset_test.go
generated
vendored
157
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/ipset_test.go
generated
vendored
@ -18,6 +18,9 @@ package ipvs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilipset "k8s.io/kubernetes/pkg/util/ipset"
|
||||
fakeipset "k8s.io/kubernetes/pkg/util/ipset/testing"
|
||||
)
|
||||
|
||||
func TestCheckIPSetVersion(t *testing.T) {
|
||||
@ -47,3 +50,157 @@ func TestCheckIPSetVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testIPSetVersion = "v6.19"
|
||||
|
||||
func TestSyncIPSetEntries(t *testing.T) {
|
||||
testCases := []struct {
|
||||
set *utilipset.IPSet
|
||||
setType utilipset.Type
|
||||
ipv6 bool
|
||||
activeEntries []string
|
||||
currentEntries []string
|
||||
expectedEntries []string
|
||||
}{
|
||||
{ // case 0
|
||||
set: &utilipset.IPSet{
|
||||
Name: "foo",
|
||||
},
|
||||
setType: utilipset.HashIPPort,
|
||||
ipv6: false,
|
||||
activeEntries: []string{"172.17.0.4,tcp:80"},
|
||||
currentEntries: nil,
|
||||
expectedEntries: []string{"172.17.0.4,tcp:80"},
|
||||
},
|
||||
{ // case 1
|
||||
set: &utilipset.IPSet{
|
||||
Name: "abz",
|
||||
},
|
||||
setType: utilipset.HashIPPort,
|
||||
ipv6: true,
|
||||
activeEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
|
||||
currentEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
|
||||
expectedEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
|
||||
},
|
||||
{ // case 2
|
||||
set: &utilipset.IPSet{
|
||||
Name: "bca",
|
||||
},
|
||||
setType: utilipset.HashIPPort,
|
||||
ipv6: false,
|
||||
activeEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
|
||||
currentEntries: []string{"172.17.0.5,udp:53"},
|
||||
expectedEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
|
||||
},
|
||||
{ // case 3
|
||||
set: &utilipset.IPSet{
|
||||
Name: "bar",
|
||||
},
|
||||
setType: utilipset.HashIPPortIP,
|
||||
ipv6: false,
|
||||
activeEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
|
||||
currentEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
|
||||
expectedEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
|
||||
},
|
||||
{ // case 4
|
||||
set: &utilipset.IPSet{
|
||||
Name: "baz",
|
||||
},
|
||||
setType: utilipset.HashIPPortIP,
|
||||
ipv6: true,
|
||||
activeEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"},
|
||||
currentEntries: []string{"1111:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8081:1111:0000:0000:0000:0202:B3FF:FE1E:8329:8081"},
|
||||
expectedEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"},
|
||||
},
|
||||
{ // case 5
|
||||
set: &utilipset.IPSet{
|
||||
Name: "NOPE",
|
||||
},
|
||||
setType: utilipset.HashIPPortIP,
|
||||
ipv6: false,
|
||||
activeEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"},
|
||||
currentEntries: nil,
|
||||
expectedEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"},
|
||||
},
|
||||
{ // case 6
|
||||
set: &utilipset.IPSet{
|
||||
Name: "ABC-DEF",
|
||||
},
|
||||
setType: utilipset.HashIPPortNet,
|
||||
ipv6: false,
|
||||
activeEntries: []string{"172.17.0.4,tcp:80,172.17.0.0/16", "172.17.0.5,tcp:80,172.17.0.0/16"},
|
||||
currentEntries: nil,
|
||||
expectedEntries: []string{"172.17.0.4,tcp:80,172.17.0.0/16", "172.17.0.5,tcp:80,172.17.0.0/16"},
|
||||
},
|
||||
{ // case 7
|
||||
set: &utilipset.IPSet{
|
||||
Name: "zar",
|
||||
},
|
||||
setType: utilipset.HashIPPortNet,
|
||||
ipv6: true,
|
||||
activeEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
|
||||
currentEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
|
||||
expectedEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
|
||||
},
|
||||
{ // case 8
|
||||
set: &utilipset.IPSet{
|
||||
Name: "bbb",
|
||||
},
|
||||
setType: utilipset.HashIPPortNet,
|
||||
ipv6: true,
|
||||
activeEntries: nil,
|
||||
currentEntries: []string{"FE80::8329,udp:8801,2001:db8::/32"},
|
||||
expectedEntries: nil,
|
||||
},
|
||||
{ // case 9
|
||||
set: &utilipset.IPSet{
|
||||
Name: "AAA",
|
||||
},
|
||||
setType: utilipset.BitmapPort,
|
||||
activeEntries: nil,
|
||||
currentEntries: []string{"80"},
|
||||
expectedEntries: nil,
|
||||
},
|
||||
{ // case 10
|
||||
set: &utilipset.IPSet{
|
||||
Name: "c-c-c",
|
||||
},
|
||||
setType: utilipset.BitmapPort,
|
||||
activeEntries: []string{"8080", "9090"},
|
||||
currentEntries: []string{"80"},
|
||||
expectedEntries: []string{"8080", "9090"},
|
||||
},
|
||||
{ // case 11
|
||||
set: &utilipset.IPSet{
|
||||
Name: "NODE-PORT",
|
||||
},
|
||||
setType: utilipset.BitmapPort,
|
||||
activeEntries: []string{"8080"},
|
||||
currentEntries: []string{"80", "9090", "8081", "8082"},
|
||||
expectedEntries: []string{"8080"},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
set := NewIPSet(fakeipset.NewFake(testIPSetVersion), testCases[i].set.Name, testCases[i].setType, testCases[i].ipv6)
|
||||
|
||||
if err := set.handle.CreateSet(&set.IPSet, true); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
for _, entry := range testCases[i].expectedEntries {
|
||||
set.handle.AddEntry(entry, testCases[i].set, true)
|
||||
}
|
||||
|
||||
set.activeEntries.Insert(testCases[i].activeEntries...)
|
||||
set.syncIPSetEntries()
|
||||
for _, entry := range testCases[i].expectedEntries {
|
||||
found, err := set.handle.TestEntry(entry, testCases[i].set.Name)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Unexpected entry 172.17.0.4,tcp:80 not found in set foo")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink.go
generated
vendored
@ -16,14 +16,21 @@ limitations under the License.
|
||||
|
||||
package ipvs
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// NetLinkHandle for revoke netlink interface
|
||||
type NetLinkHandle interface {
|
||||
// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
|
||||
// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
|
||||
EnsureAddressBind(address, devName string) (exist bool, err error)
|
||||
// UnbindAddress unbind address from the interface
|
||||
UnbindAddress(address, devName string) error
|
||||
// EnsureDummyDevice checks if dummy device is exist and, if not, create one. If the dummy device is already exist, return true.
|
||||
// EnsureDummyDevice checks if dummy device is exist and, if not, create one. If the dummy device is already exist, return true.
|
||||
EnsureDummyDevice(devName string) (exist bool, err error)
|
||||
// DeleteDummyDevice deletes the given dummy device by name.
|
||||
DeleteDummyDevice(devName string) error
|
||||
// GetLocalAddresses returns all unique local type IP addresses based on filter device interface. If filter device is not given,
|
||||
// it will list all unique local type addresses.
|
||||
GetLocalAddresses(filterDev string) (sets.String, error)
|
||||
}
|
||||
|
76
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink_linux.go
generated
vendored
76
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink_linux.go
generated
vendored
@ -21,16 +21,18 @@ package ipvs
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type netlinkHandle struct {
|
||||
netlink.Handle
|
||||
}
|
||||
|
||||
// NewNetLinkHandle will crate a new netlinkHandle
|
||||
// NewNetLinkHandle will crate a new NetLinkHandle
|
||||
func NewNetLinkHandle() NetLinkHandle {
|
||||
return &netlinkHandle{netlink.Handle{}}
|
||||
}
|
||||
@ -47,7 +49,7 @@ func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool,
|
||||
}
|
||||
if err := h.AddrAdd(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
|
||||
// "EEXIST" will be returned if the address is already bound to device
|
||||
if err == syscall.Errno(syscall.EEXIST) {
|
||||
if err == unix.EEXIST {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("error bind address: %s to interface: %s, err: %v", address, devName, err)
|
||||
@ -55,7 +57,7 @@ func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// UnbindAddress unbind address from the interface
|
||||
// UnbindAddress makes sure IP address is unbound from the network interface.
|
||||
func (h *netlinkHandle) UnbindAddress(address, devName string) error {
|
||||
dev, err := h.LinkByName(devName)
|
||||
if err != nil {
|
||||
@ -66,7 +68,9 @@ func (h *netlinkHandle) UnbindAddress(address, devName string) error {
|
||||
return fmt.Errorf("error parse ip address: %s", address)
|
||||
}
|
||||
if err := h.AddrDel(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
|
||||
return fmt.Errorf("error unbind address: %s from interface: %s, err: %v", address, devName, err)
|
||||
if err != unix.ENXIO {
|
||||
return fmt.Errorf("error unbind address: %s from interface: %s, err: %v", address, devName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -88,7 +92,11 @@ func (h *netlinkHandle) EnsureDummyDevice(devName string) (bool, error) {
|
||||
func (h *netlinkHandle) DeleteDummyDevice(devName string) error {
|
||||
link, err := h.LinkByName(devName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting a non-exist dummy device: %s", devName)
|
||||
_, ok := err.(netlink.LinkNotFoundError)
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error deleting a non-exist dummy device: %s, %v", devName, err)
|
||||
}
|
||||
dummy, ok := link.(*netlink.Dummy)
|
||||
if !ok {
|
||||
@ -96,3 +104,59 @@ func (h *netlinkHandle) DeleteDummyDevice(devName string) error {
|
||||
}
|
||||
return h.LinkDel(dummy)
|
||||
}
|
||||
|
||||
// GetLocalAddresses lists all LOCAL type IP addresses from host based on filter device.
|
||||
// If filter device is not specified, it's equivalent to exec:
|
||||
// $ ip route show table local type local proto kernel
|
||||
// 10.0.0.1 dev kube-ipvs0 scope host src 10.0.0.1
|
||||
// 10.0.0.10 dev kube-ipvs0 scope host src 10.0.0.10
|
||||
// 10.0.0.252 dev kube-ipvs0 scope host src 10.0.0.252
|
||||
// 100.106.89.164 dev eth0 scope host src 100.106.89.164
|
||||
// 127.0.0.0/8 dev lo scope host src 127.0.0.1
|
||||
// 127.0.0.1 dev lo scope host src 127.0.0.1
|
||||
// 172.17.0.1 dev docker0 scope host src 172.17.0.1
|
||||
// 192.168.122.1 dev virbr0 scope host src 192.168.122.1
|
||||
// Then cut the unique src IP fields,
|
||||
// --> result set: [10.0.0.1, 10.0.0.10, 10.0.0.252, 100.106.89.164, 127.0.0.1, 192.168.122.1]
|
||||
|
||||
// If filter device is specified, it's equivalent to exec:
|
||||
// $ ip route show table local type local proto kernel dev kube-ipvs0
|
||||
// 10.0.0.1 scope host src 10.0.0.1
|
||||
// 10.0.0.10 scope host src 10.0.0.10
|
||||
// Then cut the unique src IP fields,
|
||||
// --> result set: [10.0.0.1, 10.0.0.10]
|
||||
func (h *netlinkHandle) GetLocalAddresses(filterDev string) (sets.String, error) {
|
||||
linkIndex := -1
|
||||
if len(filterDev) != 0 {
|
||||
link, err := h.LinkByName(filterDev)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error get filter device %s, err: %v", filterDev, err)
|
||||
}
|
||||
linkIndex = link.Attrs().Index
|
||||
}
|
||||
|
||||
routeFilter := &netlink.Route{
|
||||
Table: unix.RT_TABLE_LOCAL,
|
||||
Type: unix.RTN_LOCAL,
|
||||
Protocol: unix.RTPROT_KERNEL,
|
||||
}
|
||||
filterMask := netlink.RT_FILTER_TABLE | netlink.RT_FILTER_TYPE | netlink.RT_FILTER_PROTOCOL
|
||||
|
||||
// find filter device
|
||||
if linkIndex != -1 {
|
||||
routeFilter.LinkIndex = linkIndex
|
||||
filterMask |= netlink.RT_FILTER_OIF
|
||||
}
|
||||
|
||||
routes, err := h.RouteListFiltered(netlink.FAMILY_ALL, routeFilter, filterMask)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error list route table, err: %v", err)
|
||||
}
|
||||
res := sets.NewString()
|
||||
for _, route := range routes {
|
||||
if route.Src != nil {
|
||||
res.Insert(route.Src.String())
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
7
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink_unsupported.go
generated
vendored
7
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/netlink_unsupported.go
generated
vendored
@ -20,6 +20,8 @@ package ipvs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type emptyHandle struct {
|
||||
@ -49,3 +51,8 @@ func (h *emptyHandle) EnsureDummyDevice(devName string) (bool, error) {
|
||||
func (h *emptyHandle) DeleteDummyDevice(devName string) error {
|
||||
return fmt.Errorf("netlink is not supported in this platform")
|
||||
}
|
||||
|
||||
// GetLocalAddresses is part of interface.
|
||||
func (h *emptyHandle) GetLocalAddresses(filterDev string) (sets.String, error) {
|
||||
return nil, fmt.Errorf("netlink is not supported in this platform")
|
||||
}
|
||||
|
908
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/proxier.go
generated
vendored
908
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/proxier.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1019
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/proxier_test.go
generated
vendored
1019
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/proxier_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
9
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/BUILD
generated
vendored
9
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/BUILD
generated
vendored
@ -5,6 +5,7 @@ licenses(["notice"])
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
@ -12,6 +13,7 @@ go_library(
|
||||
srcs = ["fake.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/ipvs/testing",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
@ -26,3 +28,10 @@ filegroup(
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["fake_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
|
||||
)
|
||||
|
55
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/fake.go
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/fake.go
generated
vendored
@ -16,21 +16,33 @@ limitations under the License.
|
||||
|
||||
package testing
|
||||
|
||||
//FakeNetlinkHandle mock implementation of proxy NetlinkHandle
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// FakeNetlinkHandle mock implementation of proxy NetlinkHandle
|
||||
type FakeNetlinkHandle struct {
|
||||
// localAddresses is a network interface name to all of its IP addresses map, e.g.
|
||||
// eth0 -> [1.2.3.4, 10.20.30.40]
|
||||
localAddresses map[string][]string
|
||||
}
|
||||
|
||||
//NewFakeNetlinkHandle will create a new FakeNetlinkHandle
|
||||
// NewFakeNetlinkHandle will create a new FakeNetlinkHandle
|
||||
func NewFakeNetlinkHandle() *FakeNetlinkHandle {
|
||||
return &FakeNetlinkHandle{}
|
||||
fake := &FakeNetlinkHandle{
|
||||
localAddresses: make(map[string][]string),
|
||||
}
|
||||
return fake
|
||||
}
|
||||
|
||||
//EnsureAddressBind is a mock implementation
|
||||
// EnsureAddressBind is a mock implementation
|
||||
func (h *FakeNetlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
//UnbindAddress is a mock implementation
|
||||
// UnbindAddress is a mock implementation
|
||||
func (h *FakeNetlinkHandle) UnbindAddress(address, devName string) error {
|
||||
return nil
|
||||
}
|
||||
@ -44,3 +56,36 @@ func (h *FakeNetlinkHandle) EnsureDummyDevice(devName string) (bool, error) {
|
||||
func (h *FakeNetlinkHandle) DeleteDummyDevice(devName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLocalAddresses is a mock implementation
|
||||
func (h *FakeNetlinkHandle) GetLocalAddresses(filterDev string) (sets.String, error) {
|
||||
res := sets.NewString()
|
||||
if len(filterDev) != 0 {
|
||||
// list all addresses from a given network interface.
|
||||
for _, addr := range h.localAddresses[filterDev] {
|
||||
res.Insert(addr)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
// If filterDev is not given, will list all addresses from all available network interface.
|
||||
for linkName := range h.localAddresses {
|
||||
// list all addresses from a given network interface.
|
||||
for _, addr := range h.localAddresses[linkName] {
|
||||
res.Insert(addr)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SetLocalAddresses set IP addresses to the given interface device. It's not part of interface.
|
||||
func (h *FakeNetlinkHandle) SetLocalAddresses(dev string, ips ...string) error {
|
||||
if h.localAddresses == nil {
|
||||
h.localAddresses = make(map[string][]string)
|
||||
}
|
||||
if len(dev) == 0 {
|
||||
return fmt.Errorf("device name can't be empty")
|
||||
}
|
||||
h.localAddresses[dev] = make([]string, 0)
|
||||
h.localAddresses[dev] = append(h.localAddresses[dev], ips...)
|
||||
return nil
|
||||
}
|
||||
|
49
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/fake_test.go
generated
vendored
Normal file
49
vendor/k8s.io/kubernetes/pkg/proxy/ipvs/testing/fake_test.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestSetGetLocalAddresses(t *testing.T) {
|
||||
fake := NewFakeNetlinkHandle()
|
||||
fake.SetLocalAddresses("eth0", "1.2.3.4")
|
||||
expected := sets.NewString("1.2.3.4")
|
||||
addr, _ := fake.GetLocalAddresses("eth0")
|
||||
if !reflect.DeepEqual(expected, addr) {
|
||||
t.Errorf("Unexpected mismatch, expected: %v, got: %v", expected, addr)
|
||||
}
|
||||
list, _ := fake.GetLocalAddresses("")
|
||||
if !reflect.DeepEqual(expected, list) {
|
||||
t.Errorf("Unexpected mismatch, expected: %v, got: %v", expected, list)
|
||||
}
|
||||
fake.SetLocalAddresses("lo", "127.0.0.1")
|
||||
expected = sets.NewString("127.0.0.1")
|
||||
addr, _ = fake.GetLocalAddresses("lo")
|
||||
if !reflect.DeepEqual(expected, addr) {
|
||||
t.Errorf("Unexpected mismatch, expected: %v, got: %v", expected, addr)
|
||||
}
|
||||
list, _ = fake.GetLocalAddresses("")
|
||||
expected = sets.NewString("1.2.3.4", "127.0.0.1")
|
||||
if !reflect.DeepEqual(expected, list) {
|
||||
t.Errorf("Unexpected mismatch, expected: %v, got: %v", expected, list)
|
||||
}
|
||||
}
|
344
vendor/k8s.io/kubernetes/pkg/proxy/service.go
generated
vendored
Normal file
344
vendor/k8s.io/kubernetes/pkg/proxy/service.go
generated
vendored
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/record"
|
||||
apiservice "k8s.io/kubernetes/pkg/api/service"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
)
|
||||
|
||||
// BaseServiceInfo contains base information that defines a service.
|
||||
// This could be used directly by proxier while processing services,
|
||||
// or can be used for constructing a more specific ServiceInfo struct
|
||||
// defined by the proxier if needed.
|
||||
type BaseServiceInfo struct {
|
||||
ClusterIP net.IP
|
||||
Port int
|
||||
Protocol api.Protocol
|
||||
NodePort int
|
||||
LoadBalancerStatus api.LoadBalancerStatus
|
||||
SessionAffinityType api.ServiceAffinity
|
||||
StickyMaxAgeSeconds int
|
||||
ExternalIPs []string
|
||||
LoadBalancerSourceRanges []string
|
||||
HealthCheckNodePort int
|
||||
OnlyNodeLocalEndpoints bool
|
||||
}
|
||||
|
||||
var _ ServicePort = &BaseServiceInfo{}
|
||||
|
||||
// String is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) String() string {
|
||||
return fmt.Sprintf("%s:%d/%s", info.ClusterIP, info.Port, info.Protocol)
|
||||
}
|
||||
|
||||
// ClusterIPString is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) ClusterIPString() string {
|
||||
return info.ClusterIP.String()
|
||||
}
|
||||
|
||||
// GetProtocol is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) GetProtocol() api.Protocol {
|
||||
return info.Protocol
|
||||
}
|
||||
|
||||
// GetHealthCheckNodePort is part of ServicePort interface.
|
||||
func (info *BaseServiceInfo) GetHealthCheckNodePort() int {
|
||||
return info.HealthCheckNodePort
|
||||
}
|
||||
|
||||
func (sct *ServiceChangeTracker) newBaseServiceInfo(port *api.ServicePort, service *api.Service) *BaseServiceInfo {
|
||||
onlyNodeLocalEndpoints := false
|
||||
if apiservice.RequestsOnlyLocalTraffic(service) {
|
||||
onlyNodeLocalEndpoints = true
|
||||
}
|
||||
var stickyMaxAgeSeconds int
|
||||
if service.Spec.SessionAffinity == api.ServiceAffinityClientIP {
|
||||
// Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP
|
||||
stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds)
|
||||
}
|
||||
info := &BaseServiceInfo{
|
||||
ClusterIP: net.ParseIP(service.Spec.ClusterIP),
|
||||
Port: int(port.Port),
|
||||
Protocol: port.Protocol,
|
||||
NodePort: int(port.NodePort),
|
||||
// Deep-copy in case the service instance changes
|
||||
LoadBalancerStatus: *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer),
|
||||
SessionAffinityType: service.Spec.SessionAffinity,
|
||||
StickyMaxAgeSeconds: stickyMaxAgeSeconds,
|
||||
OnlyNodeLocalEndpoints: onlyNodeLocalEndpoints,
|
||||
}
|
||||
|
||||
if sct.isIPv6Mode == nil {
|
||||
info.ExternalIPs = make([]string, len(service.Spec.ExternalIPs))
|
||||
info.LoadBalancerSourceRanges = make([]string, len(service.Spec.LoadBalancerSourceRanges))
|
||||
copy(info.LoadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges)
|
||||
copy(info.ExternalIPs, service.Spec.ExternalIPs)
|
||||
} else {
|
||||
// Filter out the incorrect IP version case.
|
||||
// If ExternalIPs and LoadBalancerSourceRanges on service contains incorrect IP versions,
|
||||
// only filter out the incorrect ones.
|
||||
var incorrectIPs []string
|
||||
info.ExternalIPs, incorrectIPs = utilnet.FilterIncorrectIPVersion(service.Spec.ExternalIPs, *sct.isIPv6Mode)
|
||||
if len(incorrectIPs) > 0 {
|
||||
utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "externalIPs", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID)
|
||||
}
|
||||
info.LoadBalancerSourceRanges, incorrectIPs = utilnet.FilterIncorrectCIDRVersion(service.Spec.LoadBalancerSourceRanges, *sct.isIPv6Mode)
|
||||
if len(incorrectIPs) > 0 {
|
||||
utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "loadBalancerSourceRanges", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID)
|
||||
}
|
||||
}
|
||||
|
||||
if apiservice.NeedsHealthCheck(service) {
|
||||
p := service.Spec.HealthCheckNodePort
|
||||
if p == 0 {
|
||||
glog.Errorf("Service %s/%s has no healthcheck nodeport", service.Namespace, service.Name)
|
||||
} else {
|
||||
info.HealthCheckNodePort = int(p)
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
type makeServicePortFunc func(*api.ServicePort, *api.Service, *BaseServiceInfo) ServicePort
|
||||
|
||||
// serviceChange contains all changes to services that happened since proxy rules were synced. For a single object,
|
||||
// changes are accumulated, i.e. previous is state from before applying the changes,
|
||||
// current is state after applying all of the changes.
|
||||
type serviceChange struct {
|
||||
previous ServiceMap
|
||||
current ServiceMap
|
||||
}
|
||||
|
||||
// ServiceChangeTracker carries state about uncommitted changes to an arbitrary number of
|
||||
// Services, keyed by their namespace and name.
|
||||
type ServiceChangeTracker struct {
|
||||
// lock protects items.
|
||||
lock sync.Mutex
|
||||
// items maps a service to its serviceChange.
|
||||
items map[types.NamespacedName]*serviceChange
|
||||
// makeServiceInfo allows proxier to inject customized information when processing service.
|
||||
makeServiceInfo makeServicePortFunc
|
||||
// isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable.
|
||||
isIPv6Mode *bool
|
||||
recorder record.EventRecorder
|
||||
}
|
||||
|
||||
// NewServiceChangeTracker initializes a ServiceChangeTracker
|
||||
func NewServiceChangeTracker(makeServiceInfo makeServicePortFunc, isIPv6Mode *bool, recorder record.EventRecorder) *ServiceChangeTracker {
|
||||
return &ServiceChangeTracker{
|
||||
items: make(map[types.NamespacedName]*serviceChange),
|
||||
makeServiceInfo: makeServiceInfo,
|
||||
isIPv6Mode: isIPv6Mode,
|
||||
recorder: recorder,
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates given service's change map based on the <previous, current> service pair. It returns true if items changed,
|
||||
// otherwise return false. Update can be used to add/update/delete items of ServiceChangeMap. For example,
|
||||
// Add item
|
||||
// - pass <nil, service> as the <previous, current> pair.
|
||||
// Update item
|
||||
// - pass <oldService, service> as the <previous, current> pair.
|
||||
// Delete item
|
||||
// - pass <service, nil> as the <previous, current> pair.
|
||||
func (sct *ServiceChangeTracker) Update(previous, current *api.Service) bool {
|
||||
svc := current
|
||||
if svc == nil {
|
||||
svc = previous
|
||||
}
|
||||
// previous == nil && current == nil is unexpected, we should return false directly.
|
||||
if svc == nil {
|
||||
return false
|
||||
}
|
||||
namespacedName := types.NamespacedName{Namespace: svc.Namespace, Name: svc.Name}
|
||||
|
||||
sct.lock.Lock()
|
||||
defer sct.lock.Unlock()
|
||||
|
||||
change, exists := sct.items[namespacedName]
|
||||
if !exists {
|
||||
change = &serviceChange{}
|
||||
change.previous = sct.serviceToServiceMap(previous)
|
||||
sct.items[namespacedName] = change
|
||||
}
|
||||
change.current = sct.serviceToServiceMap(current)
|
||||
// if change.previous equal to change.current, it means no change
|
||||
if reflect.DeepEqual(change.previous, change.current) {
|
||||
delete(sct.items, namespacedName)
|
||||
}
|
||||
return len(sct.items) > 0
|
||||
}
|
||||
|
||||
// UpdateServiceMapResult is the updated results after applying service changes.
|
||||
type UpdateServiceMapResult struct {
|
||||
// HCServiceNodePorts is a map of Service names to node port numbers which indicate the health of that Service on this Node.
|
||||
// The value(uint16) of HCServices map is the service health check node port.
|
||||
HCServiceNodePorts map[types.NamespacedName]uint16
|
||||
// UDPStaleClusterIP holds stale (no longer assigned to a Service) Service IPs that had UDP ports.
|
||||
// Callers can use this to abort timeout-waits or clear connection-tracking information.
|
||||
UDPStaleClusterIP sets.String
|
||||
}
|
||||
|
||||
// UpdateServiceMap updates ServiceMap based on the given changes.
|
||||
func UpdateServiceMap(serviceMap ServiceMap, changes *ServiceChangeTracker) (result UpdateServiceMapResult) {
|
||||
result.UDPStaleClusterIP = sets.NewString()
|
||||
serviceMap.apply(changes, result.UDPStaleClusterIP)
|
||||
|
||||
// TODO: If this will appear to be computationally expensive, consider
|
||||
// computing this incrementally similarly to serviceMap.
|
||||
result.HCServiceNodePorts = make(map[types.NamespacedName]uint16)
|
||||
for svcPortName, info := range serviceMap {
|
||||
if info.GetHealthCheckNodePort() != 0 {
|
||||
result.HCServiceNodePorts[svcPortName.NamespacedName] = uint16(info.GetHealthCheckNodePort())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ServiceMap maps a service to its ServicePort.
|
||||
type ServiceMap map[ServicePortName]ServicePort
|
||||
|
||||
// serviceToServiceMap translates a single Service object to a ServiceMap.
|
||||
//
|
||||
// NOTE: service object should NOT be modified.
|
||||
func (sct *ServiceChangeTracker) serviceToServiceMap(service *api.Service) ServiceMap {
|
||||
if service == nil {
|
||||
return nil
|
||||
}
|
||||
svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
|
||||
if utilproxy.ShouldSkipService(svcName, service) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(service.Spec.ClusterIP) != 0 {
|
||||
// Filter out the incorrect IP version case.
|
||||
// If ClusterIP on service has incorrect IP version, service itself will be ignored.
|
||||
if sct.isIPv6Mode != nil && utilnet.IsIPv6String(service.Spec.ClusterIP) != *sct.isIPv6Mode {
|
||||
utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "clusterIP", service.Spec.ClusterIP, service.Namespace, service.Name, service.UID)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
serviceMap := make(ServiceMap)
|
||||
for i := range service.Spec.Ports {
|
||||
servicePort := &service.Spec.Ports[i]
|
||||
svcPortName := ServicePortName{NamespacedName: svcName, Port: servicePort.Name}
|
||||
baseSvcInfo := sct.newBaseServiceInfo(servicePort, service)
|
||||
if sct.makeServiceInfo != nil {
|
||||
serviceMap[svcPortName] = sct.makeServiceInfo(servicePort, service, baseSvcInfo)
|
||||
} else {
|
||||
serviceMap[svcPortName] = baseSvcInfo
|
||||
}
|
||||
}
|
||||
return serviceMap
|
||||
}
|
||||
|
||||
// apply the changes to ServiceMap and update the stale udp cluster IP set. The UDPStaleClusterIP argument is passed in to store the
|
||||
// udp protocol service cluster ip when service is deleted from the ServiceMap.
|
||||
func (serviceMap *ServiceMap) apply(changes *ServiceChangeTracker, UDPStaleClusterIP sets.String) {
|
||||
changes.lock.Lock()
|
||||
defer changes.lock.Unlock()
|
||||
for _, change := range changes.items {
|
||||
serviceMap.merge(change.current)
|
||||
// filter out the Update event of current changes from previous changes before calling unmerge() so that can
|
||||
// skip deleting the Update events.
|
||||
change.previous.filter(change.current)
|
||||
serviceMap.unmerge(change.previous, UDPStaleClusterIP)
|
||||
}
|
||||
// clear changes after applying them to ServiceMap.
|
||||
changes.items = make(map[types.NamespacedName]*serviceChange)
|
||||
return
|
||||
}
|
||||
|
||||
// merge adds other ServiceMap's elements to current ServiceMap.
|
||||
// If collision, other ALWAYS win. Otherwise add the other to current.
|
||||
// In other words, if some elements in current collisions with other, update the current by other.
|
||||
// It returns a string type set which stores all the newly merged services' identifier, ServicePortName.String(), to help users
|
||||
// tell if a service is deleted or updated.
|
||||
// The returned value is one of the arguments of ServiceMap.unmerge().
|
||||
// ServiceMap A Merge ServiceMap B will do following 2 things:
|
||||
// * update ServiceMap A.
|
||||
// * produce a string set which stores all other ServiceMap's ServicePortName.String().
|
||||
// For example,
|
||||
// - A{}
|
||||
// - B{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}}
|
||||
// - A updated to be {{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}}
|
||||
// - produce string set {"ns/cluster-ip:http"}
|
||||
// - A{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 345, "UDP"}}
|
||||
// - B{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}}
|
||||
// - A updated to be {{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}}
|
||||
// - produce string set {"ns/cluster-ip:http"}
|
||||
func (sm *ServiceMap) merge(other ServiceMap) sets.String {
|
||||
// existingPorts is going to store all identifiers of all services in `other` ServiceMap.
|
||||
existingPorts := sets.NewString()
|
||||
for svcPortName, info := range other {
|
||||
// Take ServicePortName.String() as the newly merged service's identifier and put it into existingPorts.
|
||||
existingPorts.Insert(svcPortName.String())
|
||||
_, exists := (*sm)[svcPortName]
|
||||
if !exists {
|
||||
glog.V(1).Infof("Adding new service port %q at %s", svcPortName, info.String())
|
||||
} else {
|
||||
glog.V(1).Infof("Updating existing service port %q at %s", svcPortName, info.String())
|
||||
}
|
||||
(*sm)[svcPortName] = info
|
||||
}
|
||||
return existingPorts
|
||||
}
|
||||
|
||||
// filter filters out elements from ServiceMap base on given ports string sets.
|
||||
func (sm *ServiceMap) filter(other ServiceMap) {
|
||||
for svcPortName := range *sm {
|
||||
// skip the delete for Update event.
|
||||
if _, ok := other[svcPortName]; ok {
|
||||
delete(*sm, svcPortName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unmerge deletes all other ServiceMap's elements from current ServiceMap. We pass in the UDPStaleClusterIP strings sets
|
||||
// for storing the stale udp service cluster IPs. We will clear stale udp connection base on UDPStaleClusterIP later
|
||||
func (sm *ServiceMap) unmerge(other ServiceMap, UDPStaleClusterIP sets.String) {
|
||||
for svcPortName := range other {
|
||||
info, exists := (*sm)[svcPortName]
|
||||
if exists {
|
||||
glog.V(1).Infof("Removing service port %q", svcPortName)
|
||||
if info.GetProtocol() == api.ProtocolUDP {
|
||||
UDPStaleClusterIP.Insert(info.ClusterIPString())
|
||||
}
|
||||
delete(*sm, svcPortName)
|
||||
} else {
|
||||
glog.Errorf("Service port %q doesn't exists", svcPortName)
|
||||
}
|
||||
}
|
||||
}
|
649
vendor/k8s.io/kubernetes/pkg/proxy/service_test.go
generated
vendored
Normal file
649
vendor/k8s.io/kubernetes/pkg/proxy/service_test.go
generated
vendored
Normal file
@ -0,0 +1,649 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
const testHostname = "test-hostname"
|
||||
|
||||
func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*BaseServiceInfo)) *BaseServiceInfo {
|
||||
info := &BaseServiceInfo{
|
||||
ClusterIP: net.ParseIP(clusterIP),
|
||||
Port: port,
|
||||
Protocol: api.Protocol(protocol),
|
||||
}
|
||||
if healthcheckNodePort != 0 {
|
||||
info.HealthCheckNodePort = healthcheckNodePort
|
||||
}
|
||||
for _, svcInfoFunc := range svcInfoFuncs {
|
||||
svcInfoFunc(info)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func makeTestService(namespace, name string, svcFunc func(*api.Service)) *api.Service {
|
||||
svc := &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: api.ServiceSpec{},
|
||||
Status: api.ServiceStatus{},
|
||||
}
|
||||
svcFunc(svc)
|
||||
return svc
|
||||
}
|
||||
|
||||
func addTestPort(array []api.ServicePort, name string, protocol api.Protocol, port, nodeport int32, targetPort int) []api.ServicePort {
|
||||
svcPort := api.ServicePort{
|
||||
Name: name,
|
||||
Protocol: protocol,
|
||||
Port: port,
|
||||
NodePort: nodeport,
|
||||
TargetPort: intstr.FromInt(targetPort),
|
||||
}
|
||||
return append(array, svcPort)
|
||||
}
|
||||
|
||||
func makeNSN(namespace, name string) types.NamespacedName {
|
||||
return types.NamespacedName{Namespace: namespace, Name: name}
|
||||
}
|
||||
|
||||
func makeServicePortName(ns, name, port string) ServicePortName {
|
||||
return ServicePortName{
|
||||
NamespacedName: makeNSN(ns, name),
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceToServiceMap(t *testing.T) {
|
||||
svcTracker := NewServiceChangeTracker(nil, nil, nil)
|
||||
|
||||
trueVal := true
|
||||
falseVal := false
|
||||
testClusterIPv4 := "10.0.0.1"
|
||||
testExternalIPv4 := "8.8.8.8"
|
||||
testSourceRangeIPv4 := "0.0.0.0/1"
|
||||
testClusterIPv6 := "2001:db8:85a3:0:0:8a2e:370:7334"
|
||||
testExternalIPv6 := "2001:db8:85a3:0:0:8a2e:370:7335"
|
||||
testSourceRangeIPv6 := "2001:db8::/32"
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
service *api.Service
|
||||
expected map[ServicePortName]*BaseServiceInfo
|
||||
isIPv6Mode *bool
|
||||
}{
|
||||
{
|
||||
desc: "nothing",
|
||||
service: nil,
|
||||
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||
},
|
||||
{
|
||||
desc: "headless 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, "rpc", "UDP", 1234, 0, 0)
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||
},
|
||||
{
|
||||
desc: "headless service without port",
|
||||
service: makeTestService("ns2", "headless-without-port", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = api.ClusterIPNone
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||
},
|
||||
{
|
||||
desc: "cluster ip service",
|
||||
service: makeTestService("ns2", "cluster-ip", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = "172.16.55.4"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("ns2", "cluster-ip", "p1"): makeTestServiceInfo("172.16.55.4", 1234, "UDP", 0),
|
||||
makeServicePortName("ns2", "cluster-ip", "p2"): makeTestServiceInfo("172.16.55.4", 1235, "UDP", 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "nodeport service",
|
||||
service: makeTestService("ns2", "node-port", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeNodePort
|
||||
svc.Spec.ClusterIP = "172.16.55.10"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("ns2", "node-port", "port1"): makeTestServiceInfo("172.16.55.10", 345, "UDP", 0),
|
||||
makeServicePortName("ns2", "node-port", "port2"): makeTestServiceInfo("172.16.55.10", 344, "TCP", 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "load balancer service",
|
||||
service: makeTestService("ns1", "load-balancer", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
svc.Spec.ClusterIP = "172.16.55.11"
|
||||
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
|
||||
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "10.1.2.4"},
|
||||
},
|
||||
}
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("ns1", "load-balancer", "port3"): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0),
|
||||
makeServicePortName("ns1", "load-balancer", "port4"): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "load balancer service with only local traffic policy",
|
||||
service: makeTestService("ns1", "only-local-load-balancer", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
svc.Spec.ClusterIP = "172.16.55.12"
|
||||
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portx", "UDP", 8677, 30063, 7002)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "porty", "UDP", 8678, 30064, 7003)
|
||||
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "10.1.2.3"},
|
||||
},
|
||||
}
|
||||
svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal
|
||||
svc.Spec.HealthCheckNodePort = 345
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("ns1", "only-local-load-balancer", "portx"): makeTestServiceInfo("172.16.55.12", 8677, "UDP", 345),
|
||||
makeServicePortName("ns1", "only-local-load-balancer", "porty"): makeTestServiceInfo("172.16.55.12", 8678, "UDP", 345),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "external name service",
|
||||
service: makeTestService("ns2", "external-name", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeExternalName
|
||||
svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
|
||||
svc.Spec.ExternalName = "foo2.bar.com"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portz", "UDP", 1235, 5321, 0)
|
||||
}),
|
||||
expected: map[ServicePortName]*BaseServiceInfo{},
|
||||
},
|
||||
{
|
||||
desc: "service with ipv6 clusterIP under ipv4 mode, service should be filtered",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "invalidIPv6InIPV4Mode",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv6,
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isIPv6Mode: &falseVal,
|
||||
},
|
||||
{
|
||||
desc: "service with ipv4 clusterIP under ipv6 mode, service should be filtered",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "invalidIPv4InIPV6Mode",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv4,
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isIPv6Mode: &trueVal,
|
||||
},
|
||||
{
|
||||
desc: "service with ipv4 configurations under ipv4 mode",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validIPv4",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv4,
|
||||
ExternalIPs: []string{testExternalIPv4},
|
||||
LoadBalancerSourceRanges: []string{testSourceRangeIPv4},
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("test", "validIPv4", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) {
|
||||
info.ExternalIPs = []string{testExternalIPv4}
|
||||
info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4}
|
||||
}),
|
||||
},
|
||||
isIPv6Mode: &falseVal,
|
||||
},
|
||||
{
|
||||
desc: "service with ipv6 configurations under ipv6 mode",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validIPv6",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv6,
|
||||
ExternalIPs: []string{testExternalIPv6},
|
||||
LoadBalancerSourceRanges: []string{testSourceRangeIPv6},
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("test", "validIPv6", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) {
|
||||
info.ExternalIPs = []string{testExternalIPv6}
|
||||
info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6}
|
||||
}),
|
||||
},
|
||||
isIPv6Mode: &trueVal,
|
||||
},
|
||||
{
|
||||
desc: "service with both ipv4 and ipv6 configurations under ipv4 mode, ipv6 fields should be filtered",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "filterIPv6InIPV4Mode",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv4,
|
||||
ExternalIPs: []string{testExternalIPv4, testExternalIPv6},
|
||||
LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) {
|
||||
info.ExternalIPs = []string{testExternalIPv4}
|
||||
info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4}
|
||||
}),
|
||||
},
|
||||
isIPv6Mode: &falseVal,
|
||||
},
|
||||
{
|
||||
desc: "service with both ipv4 and ipv6 configurations under ipv6 mode, ipv4 fields should be filtered",
|
||||
service: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "filterIPv4InIPV6Mode",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: testClusterIPv6,
|
||||
ExternalIPs: []string{testExternalIPv4, testExternalIPv6},
|
||||
LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "testPort",
|
||||
Port: int32(12345),
|
||||
Protocol: api.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[ServicePortName]*BaseServiceInfo{
|
||||
makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) {
|
||||
info.ExternalIPs = []string{testExternalIPv6}
|
||||
info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6}
|
||||
}),
|
||||
},
|
||||
isIPv6Mode: &trueVal,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
svcTracker.isIPv6Mode = tc.isIPv6Mode
|
||||
// outputs
|
||||
newServices := svcTracker.serviceToServiceMap(tc.service)
|
||||
|
||||
if len(newServices) != len(tc.expected) {
|
||||
t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newServices), spew.Sdump(newServices))
|
||||
}
|
||||
for svcKey, expectedInfo := range tc.expected {
|
||||
svcInfo := newServices[svcKey].(*BaseServiceInfo)
|
||||
if !svcInfo.ClusterIP.Equal(expectedInfo.ClusterIP) ||
|
||||
svcInfo.Port != expectedInfo.Port ||
|
||||
svcInfo.Protocol != expectedInfo.Protocol ||
|
||||
svcInfo.HealthCheckNodePort != expectedInfo.HealthCheckNodePort ||
|
||||
!sets.NewString(svcInfo.ExternalIPs...).Equal(sets.NewString(expectedInfo.ExternalIPs...)) ||
|
||||
!sets.NewString(svcInfo.LoadBalancerSourceRanges...).Equal(sets.NewString(expectedInfo.LoadBalancerSourceRanges...)) {
|
||||
t.Errorf("[%s] expected new[%v]to be %v, got %v", tc.desc, svcKey, expectedInfo, *svcInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type FakeProxier struct {
|
||||
endpointsChanges *EndpointChangeTracker
|
||||
serviceChanges *ServiceChangeTracker
|
||||
serviceMap ServiceMap
|
||||
endpointsMap EndpointsMap
|
||||
hostname string
|
||||
}
|
||||
|
||||
func newFakeProxier() *FakeProxier {
|
||||
return &FakeProxier{
|
||||
serviceMap: make(ServiceMap),
|
||||
serviceChanges: NewServiceChangeTracker(nil, nil, nil),
|
||||
endpointsMap: make(EndpointsMap),
|
||||
endpointsChanges: NewEndpointChangeTracker(testHostname, nil, nil, nil),
|
||||
}
|
||||
}
|
||||
|
||||
func makeServiceMap(fake *FakeProxier, allServices ...*api.Service) {
|
||||
for i := range allServices {
|
||||
fake.addService(allServices[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (fake *FakeProxier) addService(service *api.Service) {
|
||||
fake.serviceChanges.Update(nil, service)
|
||||
}
|
||||
|
||||
func (fake *FakeProxier) updateService(oldService *api.Service, service *api.Service) {
|
||||
fake.serviceChanges.Update(oldService, service)
|
||||
}
|
||||
|
||||
func (fake *FakeProxier) deleteService(service *api.Service) {
|
||||
fake.serviceChanges.Update(service, nil)
|
||||
}
|
||||
|
||||
func TestUpdateServiceMapHeadless(t *testing.T) {
|
||||
fp := newFakeProxier()
|
||||
|
||||
makeServiceMap(fp,
|
||||
makeTestService("ns2", "headless", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = api.ClusterIPNone
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
|
||||
}),
|
||||
makeTestService("ns2", "headless-without-port", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = api.ClusterIPNone
|
||||
}),
|
||||
)
|
||||
|
||||
// Headless service should be ignored
|
||||
result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 0 {
|
||||
t.Errorf("expected service map length 0, got %d", len(fp.serviceMap))
|
||||
}
|
||||
|
||||
// No proxied services, so no healthchecks
|
||||
if len(result.HCServiceNodePorts) != 0 {
|
||||
t.Errorf("expected healthcheck ports length 0, got %d", len(result.HCServiceNodePorts))
|
||||
}
|
||||
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateServiceTypeExternalName(t *testing.T) {
|
||||
fp := newFakeProxier()
|
||||
|
||||
makeServiceMap(fp,
|
||||
makeTestService("ns2", "external-name", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeExternalName
|
||||
svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
|
||||
svc.Spec.ExternalName = "foo2.bar.com"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blah", "UDP", 1235, 5321, 0)
|
||||
}),
|
||||
)
|
||||
|
||||
result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 0 {
|
||||
t.Errorf("expected service map length 0, got %v", fp.serviceMap)
|
||||
}
|
||||
// No proxied services, so no healthchecks
|
||||
if len(result.HCServiceNodePorts) != 0 {
|
||||
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildServiceMapAddRemove(t *testing.T) {
|
||||
fp := newFakeProxier()
|
||||
|
||||
services := []*api.Service{
|
||||
makeTestService("ns2", "cluster-ip", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = "172.16.55.4"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 1234, 4321, 0)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "UDP", 1235, 5321, 0)
|
||||
}),
|
||||
makeTestService("ns2", "node-port", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeNodePort
|
||||
svc.Spec.ClusterIP = "172.16.55.10"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
|
||||
}),
|
||||
makeTestService("ns1", "load-balancer", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
svc.Spec.ClusterIP = "172.16.55.11"
|
||||
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, "baz", "UDP", 8676, 30062, 7001)
|
||||
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "10.1.2.4"},
|
||||
},
|
||||
}
|
||||
}),
|
||||
makeTestService("ns1", "only-local-load-balancer", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
svc.Spec.ClusterIP = "172.16.55.12"
|
||||
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, "baz", "UDP", 8678, 30064, 7003)
|
||||
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "10.1.2.3"},
|
||||
},
|
||||
}
|
||||
svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal
|
||||
svc.Spec.HealthCheckNodePort = 345
|
||||
}),
|
||||
}
|
||||
|
||||
for i := range services {
|
||||
fp.addService(services[i])
|
||||
}
|
||||
result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 8 {
|
||||
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
|
||||
}
|
||||
|
||||
// The only-local-loadbalancer ones get added
|
||||
if len(result.HCServiceNodePorts) != 1 {
|
||||
t.Errorf("expected 1 healthcheck port, got %v", result.HCServiceNodePorts)
|
||||
} else {
|
||||
nsn := makeNSN("ns1", "only-local-load-balancer")
|
||||
if port, found := result.HCServiceNodePorts[nsn]; !found || port != 345 {
|
||||
t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, result.HCServiceNodePorts)
|
||||
}
|
||||
}
|
||||
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
// Services only added, so nothing stale yet
|
||||
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
|
||||
}
|
||||
|
||||
// Remove some stuff
|
||||
// oneService is a modification of services[0] with removed first port.
|
||||
oneService := makeTestService("ns2", "cluster-ip", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = "172.16.55.4"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
|
||||
})
|
||||
|
||||
fp.updateService(services[0], oneService)
|
||||
fp.deleteService(services[1])
|
||||
fp.deleteService(services[2])
|
||||
fp.deleteService(services[3])
|
||||
|
||||
result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 1 {
|
||||
t.Errorf("expected service map length 1, got %v", fp.serviceMap)
|
||||
}
|
||||
|
||||
if len(result.HCServiceNodePorts) != 0 {
|
||||
t.Errorf("expected 0 healthcheck ports, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
|
||||
// All services but one were deleted. While you'd expect only the ClusterIPs
|
||||
// from the three deleted services here, we still have the ClusterIP for
|
||||
// the not-deleted service, because one of it's ServicePorts was deleted.
|
||||
expectedStaleUDPServices := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"}
|
||||
if len(result.UDPStaleClusterIP) != len(expectedStaleUDPServices) {
|
||||
t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.UDPStaleClusterIP.UnsortedList())
|
||||
}
|
||||
for _, ip := range expectedStaleUDPServices {
|
||||
if !result.UDPStaleClusterIP.Has(ip) {
|
||||
t.Errorf("expected stale UDP service service %s", ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildServiceMapServiceUpdate(t *testing.T) {
|
||||
fp := newFakeProxier()
|
||||
|
||||
servicev1 := makeTestService("ns1", "svc1", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeClusterIP
|
||||
svc.Spec.ClusterIP = "172.16.55.4"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 0)
|
||||
})
|
||||
servicev2 := makeTestService("ns1", "svc1", func(svc *api.Service) {
|
||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
||||
svc.Spec.ClusterIP = "172.16.55.4"
|
||||
svc.Spec.LoadBalancerIP = "5.6.7.8"
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 7002)
|
||||
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 7003)
|
||||
svc.Status.LoadBalancer = api.LoadBalancerStatus{
|
||||
Ingress: []api.LoadBalancerIngress{
|
||||
{IP: "10.1.2.3"},
|
||||
},
|
||||
}
|
||||
svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal
|
||||
svc.Spec.HealthCheckNodePort = 345
|
||||
})
|
||||
|
||||
fp.addService(servicev1)
|
||||
|
||||
result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 2 {
|
||||
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
|
||||
}
|
||||
if len(result.HCServiceNodePorts) != 0 {
|
||||
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
// Services only added, so nothing stale yet
|
||||
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
|
||||
}
|
||||
|
||||
// Change service to load-balancer
|
||||
fp.updateService(servicev1, servicev2)
|
||||
result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 2 {
|
||||
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
|
||||
}
|
||||
if len(result.HCServiceNodePorts) != 1 {
|
||||
t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
|
||||
}
|
||||
|
||||
// No change; make sure the service map stays the same and there are
|
||||
// no health-check changes
|
||||
fp.updateService(servicev2, servicev2)
|
||||
result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 2 {
|
||||
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
|
||||
}
|
||||
if len(result.HCServiceNodePorts) != 1 {
|
||||
t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
|
||||
}
|
||||
|
||||
// And back to ClusterIP
|
||||
fp.updateService(servicev2, servicev1)
|
||||
result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
|
||||
if len(fp.serviceMap) != 2 {
|
||||
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
|
||||
}
|
||||
if len(result.HCServiceNodePorts) != 0 {
|
||||
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
|
||||
}
|
||||
if len(result.UDPStaleClusterIP) != 0 {
|
||||
// Services only added, so nothing stale yet
|
||||
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
|
||||
}
|
||||
}
|
39
vendor/k8s.io/kubernetes/pkg/proxy/types.go
generated
vendored
39
vendor/k8s.io/kubernetes/pkg/proxy/types.go
generated
vendored
@ -20,11 +20,12 @@ import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// ProxyProvider is the interface provided by proxier implementations.
|
||||
type ProxyProvider interface {
|
||||
// Sync immediately synchronizes the ProxyProvider's current state to iptables.
|
||||
// Sync immediately synchronizes the ProxyProvider's current state to proxy rules.
|
||||
Sync()
|
||||
// SyncLoop runs periodic work.
|
||||
// This is expected to run as a goroutine or as the main loop of the app.
|
||||
@ -33,7 +34,7 @@ type ProxyProvider interface {
|
||||
}
|
||||
|
||||
// ServicePortName carries a namespace + name + portname. This is the unique
|
||||
// identfier for a load-balanced service.
|
||||
// identifier for a load-balanced service.
|
||||
type ServicePortName struct {
|
||||
types.NamespacedName
|
||||
Port string
|
||||
@ -42,3 +43,37 @@ type ServicePortName struct {
|
||||
func (spn ServicePortName) String() string {
|
||||
return fmt.Sprintf("%s:%s", spn.NamespacedName.String(), spn.Port)
|
||||
}
|
||||
|
||||
// ServicePort is an interface which abstracts information about a service.
|
||||
type ServicePort interface {
|
||||
// String returns service string. An example format can be: `IP:Port/Protocol`.
|
||||
String() string
|
||||
// ClusterIPString returns service cluster IP in string format.
|
||||
ClusterIPString() string
|
||||
// GetProtocol returns service protocol.
|
||||
GetProtocol() api.Protocol
|
||||
// GetHealthCheckNodePort returns service health check node port if present. If return 0, it means not present.
|
||||
GetHealthCheckNodePort() int
|
||||
}
|
||||
|
||||
// Endpoint in an interface which abstracts information about an endpoint.
|
||||
// TODO: Rename functions to be consistent with ServicePort.
|
||||
type Endpoint interface {
|
||||
// String returns endpoint string. An example format can be: `IP:Port`.
|
||||
// We take the returned value as ServiceEndpoint.Endpoint.
|
||||
String() string
|
||||
// GetIsLocal returns true if the endpoint is running in same host as kube-proxy, otherwise returns false.
|
||||
GetIsLocal() bool
|
||||
// IP returns IP part of the endpoint.
|
||||
IP() string
|
||||
// Port returns the Port part of the endpoint.
|
||||
Port() (int, error)
|
||||
// Equal checks if two endpoints are equal.
|
||||
Equal(Endpoint) bool
|
||||
}
|
||||
|
||||
// ServiceEndpoint is used to identify a service and one of its endpoint pair.
|
||||
type ServiceEndpoint struct {
|
||||
Endpoint string
|
||||
ServicePortName ServicePortName
|
||||
}
|
||||
|
73
vendor/k8s.io/kubernetes/pkg/proxy/userspace/BUILD
generated
vendored
73
vendor/k8s.io/kubernetes/pkg/proxy/userspace/BUILD
generated
vendored
@ -13,11 +13,40 @@ go_library(
|
||||
"port_allocator.go",
|
||||
"proxier.go",
|
||||
"proxysocket.go",
|
||||
"rlimit.go",
|
||||
"roundrobin.go",
|
||||
"udp_server.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:nacl": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:plan9": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:solaris": [
|
||||
"rlimit.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"rlimit_windows.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
@ -28,10 +57,11 @@ go_library(
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/util:go_default_library",
|
||||
"//pkg/util/conntrack:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/slice:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
@ -39,7 +69,39 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:nacl": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:plan9": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:solaris": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
@ -49,8 +111,7 @@ go_test(
|
||||
"proxier_test.go",
|
||||
"roundrobin_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/userspace",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
|
29
vendor/k8s.io/kubernetes/pkg/proxy/userspace/proxier.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/proxy/userspace/proxier.go
generated
vendored
@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
@ -36,6 +37,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||
"k8s.io/kubernetes/pkg/util/conntrack"
|
||||
"k8s.io/kubernetes/pkg/util/iptables"
|
||||
utilexec "k8s.io/utils/exec"
|
||||
)
|
||||
@ -123,7 +125,7 @@ type portMapKey struct {
|
||||
}
|
||||
|
||||
func (k *portMapKey) String() string {
|
||||
return fmt.Sprintf("%s:%d/%s", k.ip, k.port, k.protocol)
|
||||
return fmt.Sprintf("%s/%s", net.JoinHostPort(k.ip, strconv.Itoa(k.port)), k.protocol)
|
||||
}
|
||||
|
||||
// A value for the portMap
|
||||
@ -153,15 +155,15 @@ func IsProxyLocked(err error) bool {
|
||||
// if iptables fails to update or acquire the initial lock. Once a proxier is
|
||||
// created, it will keep iptables up to date in the background and will not
|
||||
// terminate if a particular iptables call fails.
|
||||
func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration) (*Proxier, error) {
|
||||
return NewCustomProxier(loadBalancer, listenIP, iptables, exec, pr, syncPeriod, minSyncPeriod, udpIdleTimeout, newProxySocket)
|
||||
func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, nodePortAddresses []string) (*Proxier, error) {
|
||||
return NewCustomProxier(loadBalancer, listenIP, iptables, exec, pr, syncPeriod, minSyncPeriod, udpIdleTimeout, nodePortAddresses, newProxySocket)
|
||||
}
|
||||
|
||||
// NewCustomProxier functions similarly to NewProxier, returing a new Proxier
|
||||
// NewCustomProxier functions similarly to NewProxier, returning a new Proxier
|
||||
// for the given LoadBalancer and address. The new proxier is constructed using
|
||||
// the ProxySocket constructor provided, however, instead of constructing the
|
||||
// default ProxySockets.
|
||||
func NewCustomProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, makeProxySocket ProxySocketFunc) (*Proxier, error) {
|
||||
func NewCustomProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, nodePortAddresses []string, makeProxySocket ProxySocketFunc) (*Proxier, error) {
|
||||
if listenIP.Equal(localhostIPv4) || listenIP.Equal(localhostIPv6) {
|
||||
return nil, ErrProxyOnLocalhost
|
||||
}
|
||||
@ -170,7 +172,7 @@ func NewCustomProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptab
|
||||
// try to find a suitable host IP address from network interfaces.
|
||||
var err error
|
||||
hostIP := listenIP
|
||||
if hostIP.Equal(net.IPv4zero) {
|
||||
if hostIP.Equal(net.IPv4zero) || hostIP.Equal(net.IPv6zero) {
|
||||
hostIP, err = utilnet.ChooseHostInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to select a host interface: %v", err)
|
||||
@ -435,7 +437,7 @@ func (proxier *Proxier) mergeService(service *api.Service) sets.String {
|
||||
}
|
||||
|
||||
serviceIP := net.ParseIP(service.Spec.ClusterIP)
|
||||
glog.V(1).Infof("Adding new service %q at %s:%d/%s", serviceName, serviceIP, servicePort.Port, servicePort.Protocol)
|
||||
glog.V(1).Infof("Adding new service %q at %s/%s", serviceName, net.JoinHostPort(serviceIP.String(), strconv.Itoa(int(servicePort.Port))), servicePort.Protocol)
|
||||
info, err = proxier.addServiceOnPort(serviceName, servicePort.Protocol, proxyPort, proxier.udpIdleTimeout)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to start proxy for %q: %v", serviceName, err)
|
||||
@ -504,7 +506,7 @@ func (proxier *Proxier) unmergeService(service *api.Service, existingPorts sets.
|
||||
proxier.loadBalancer.DeleteService(serviceName)
|
||||
}
|
||||
for _, svcIP := range staleUDPServices.UnsortedList() {
|
||||
if err := utilproxy.ClearUDPConntrackForIP(proxier.exec, svcIP); err != nil {
|
||||
if err := conntrack.ClearEntriesForIP(proxier.exec, svcIP, v1.ProtocolUDP); err != nil {
|
||||
glog.Errorf("Failed to delete stale service IP %s connections, error: %v", svcIP, err)
|
||||
}
|
||||
}
|
||||
@ -597,13 +599,14 @@ func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, prox
|
||||
|
||||
// Handle traffic from containers.
|
||||
args := proxier.iptablesContainerPortalArgs(portal.ip, portal.isExternal, false, portal.port, protocol, proxyIP, proxyPort, name)
|
||||
portalAddress := net.JoinHostPort(portal.ip.String(), strconv.Itoa(portal.port))
|
||||
existed, err := proxier.iptables.EnsureRule(iptables.Append, iptables.TableNAT, iptablesContainerPortalChain, args...)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to install iptables %s rule for service %q, args:%v", iptablesContainerPortalChain, name, args)
|
||||
return err
|
||||
}
|
||||
if !existed {
|
||||
glog.V(3).Infof("Opened iptables from-containers portal for service %q on %s %s:%d", name, protocol, portal.ip, portal.port)
|
||||
glog.V(3).Infof("Opened iptables from-containers portal for service %q on %s %s", name, protocol, portalAddress)
|
||||
}
|
||||
if portal.isExternal {
|
||||
args := proxier.iptablesContainerPortalArgs(portal.ip, false, true, portal.port, protocol, proxyIP, proxyPort, name)
|
||||
@ -613,7 +616,7 @@ func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, prox
|
||||
return err
|
||||
}
|
||||
if !existed {
|
||||
glog.V(3).Infof("Opened iptables from-containers portal for service %q on %s %s:%d for local traffic", name, protocol, portal.ip, portal.port)
|
||||
glog.V(3).Infof("Opened iptables from-containers portal for service %q on %s %s for local traffic", name, protocol, portalAddress)
|
||||
}
|
||||
|
||||
args = proxier.iptablesHostPortalArgs(portal.ip, true, portal.port, protocol, proxyIP, proxyPort, name)
|
||||
@ -623,7 +626,7 @@ func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, prox
|
||||
return err
|
||||
}
|
||||
if !existed {
|
||||
glog.V(3).Infof("Opened iptables from-host portal for service %q on %s %s:%d for dst-local traffic", name, protocol, portal.ip, portal.port)
|
||||
glog.V(3).Infof("Opened iptables from-host portal for service %q on %s %s for dst-local traffic", name, protocol, portalAddress)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -636,7 +639,7 @@ func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, prox
|
||||
return err
|
||||
}
|
||||
if !existed {
|
||||
glog.V(3).Infof("Opened iptables from-host portal for service %q on %s %s:%d", name, protocol, portal.ip, portal.port)
|
||||
glog.V(3).Infof("Opened iptables from-host portal for service %q on %s %s", name, protocol, portalAddress)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -964,7 +967,7 @@ func iptablesCommonPortalArgs(destIP net.IP, addPhysicalInterfaceMatch bool, add
|
||||
}
|
||||
|
||||
if destIP != nil {
|
||||
args = append(args, "-d", fmt.Sprintf("%s/32", destIP.String()))
|
||||
args = append(args, "-d", utilproxy.ToCIDR(destIP))
|
||||
}
|
||||
|
||||
if addPhysicalInterfaceMatch {
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/proxy/userspace/proxysocket.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/proxy/userspace/proxysocket.go
generated
vendored
@ -87,7 +87,7 @@ func (tcp *tcpProxySocket) ListenPort() int {
|
||||
}
|
||||
|
||||
// TryConnectEndpoints attempts to connect to the next available endpoint for the given service, cycling
|
||||
// through until it is able to successully connect, or it has tried with all timeouts in EndpointDialTimeouts.
|
||||
// through until it is able to successfully connect, or it has tried with all timeouts in EndpointDialTimeouts.
|
||||
func TryConnectEndpoints(service proxy.ServicePortName, srcAddr net.Addr, protocol string, loadBalancer LoadBalancer) (out net.Conn, err error) {
|
||||
sessionAffinityReset := false
|
||||
for _, dialTimeout := range EndpointDialTimeouts {
|
||||
|
20
vendor/k8s.io/kubernetes/pkg/proxy/util/BUILD
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/proxy/util/BUILD
generated
vendored
@ -3,8 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conntrack.go",
|
||||
"endpoints.go",
|
||||
"network.go",
|
||||
"port.go",
|
||||
"utils.go",
|
||||
],
|
||||
@ -13,28 +13,29 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/util/net:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"conntrack_test.go",
|
||||
"endpoints_test.go",
|
||||
"port_test.go",
|
||||
"utils_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/util",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy/util/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -47,7 +48,10 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/proxy/util/testing:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
105
vendor/k8s.io/kubernetes/pkg/proxy/util/conntrack.go
generated
vendored
105
vendor/k8s.io/kubernetes/pkg/proxy/util/conntrack.go
generated
vendored
@ -1,105 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// Utilities for dealing with conntrack
|
||||
|
||||
const NoConnectionToDelete = "0 flow entries have been deleted"
|
||||
|
||||
func IsIPv6(netIP net.IP) bool {
|
||||
return netIP != nil && netIP.To4() == nil
|
||||
}
|
||||
|
||||
func IsIPv6String(ip string) bool {
|
||||
netIP := net.ParseIP(ip)
|
||||
return IsIPv6(netIP)
|
||||
}
|
||||
|
||||
func parametersWithFamily(isIPv6 bool, parameters ...string) []string {
|
||||
if isIPv6 {
|
||||
parameters = append(parameters, "-f", "ipv6")
|
||||
}
|
||||
return parameters
|
||||
}
|
||||
|
||||
// ClearUDPConntrackForIP uses the conntrack tool to delete the conntrack entries
|
||||
// for the UDP connections specified by the given service IP
|
||||
func ClearUDPConntrackForIP(execer exec.Interface, ip string) error {
|
||||
parameters := parametersWithFamily(IsIPv6String(ip), "-D", "--orig-dst", ip, "-p", "udp")
|
||||
err := ExecConntrackTool(execer, parameters...)
|
||||
if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) {
|
||||
// TODO: Better handling for deletion failure. When failure occur, stale udp connection may not get flushed.
|
||||
// These stale udp connection will keep black hole traffic. Making this a best effort operation for now, since it
|
||||
// is expensive to baby-sit all udp connections to kubernetes services.
|
||||
return fmt.Errorf("error deleting connection tracking state for UDP service IP: %s, error: %v", ip, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecConntrackTool executes the conntrack tool using the given parameters
|
||||
func ExecConntrackTool(execer exec.Interface, parameters ...string) error {
|
||||
conntrackPath, err := execer.LookPath("conntrack")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error looking for path of conntrack: %v", err)
|
||||
}
|
||||
output, err := execer.Command(conntrackPath, parameters...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("conntrack command returned: %q, error message: %s", string(output), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearUDPConntrackForPort uses the conntrack tool to delete the conntrack entries
|
||||
// for the UDP connections specified by the port.
|
||||
// When a packet arrives, it will not go through NAT table again, because it is not "the first" packet.
|
||||
// The solution is clearing the conntrack. Known issues:
|
||||
// https://github.com/docker/docker/issues/8795
|
||||
// https://github.com/kubernetes/kubernetes/issues/31983
|
||||
func ClearUDPConntrackForPort(execer exec.Interface, port int, isIPv6 bool) error {
|
||||
if port <= 0 {
|
||||
return fmt.Errorf("Wrong port number. The port number must be greater than zero")
|
||||
}
|
||||
parameters := parametersWithFamily(isIPv6, "-D", "-p", "udp", "--dport", strconv.Itoa(port))
|
||||
err := ExecConntrackTool(execer, parameters...)
|
||||
if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) {
|
||||
return fmt.Errorf("error deleting conntrack entries for UDP port: %d, error: %v", port, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearUDPConntrackForPeers uses the conntrack tool to delete the conntrack entries
|
||||
// for the UDP connections specified by the {origin, dest} IP pair.
|
||||
func ClearUDPConntrackForPeers(execer exec.Interface, origin, dest string) error {
|
||||
parameters := parametersWithFamily(IsIPv6String(origin), "-D", "--orig-dst", origin, "--dst-nat", dest, "-p", "udp")
|
||||
err := ExecConntrackTool(execer, parameters...)
|
||||
if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) {
|
||||
// TODO: Better handling for deletion failure. When failure occur, stale udp connection may not get flushed.
|
||||
// These stale udp connection will keep black hole traffic. Making this a best effort operation for now, since it
|
||||
// is expensive to baby sit all udp connections to kubernetes services.
|
||||
return fmt.Errorf("error deleting conntrack entries for UDP peer {%s, %s}, error: %v", origin, dest, err)
|
||||
}
|
||||
return nil
|
||||
}
|
331
vendor/k8s.io/kubernetes/pkg/proxy/util/conntrack_test.go
generated
vendored
331
vendor/k8s.io/kubernetes/pkg/proxy/util/conntrack_test.go
generated
vendored
@ -1,331 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/utils/exec"
|
||||
fakeexec "k8s.io/utils/exec/testing"
|
||||
)
|
||||
|
||||
func familyParamStr(isIPv6 bool) string {
|
||||
if isIPv6 {
|
||||
return " -f ipv6"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func TestExecConntrackTool(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) {
|
||||
return []byte(""), fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
|
||||
},
|
||||
},
|
||||
}
|
||||
fexec := fakeexec.FakeExec{
|
||||
CommandScript: []fakeexec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
|
||||
}
|
||||
|
||||
testCases := [][]string{
|
||||
{"-L", "-p", "udp"},
|
||||
{"-D", "-p", "udp", "-d", "10.0.240.1"},
|
||||
{"-D", "-p", "udp", "--orig-dst", "10.240.0.2", "--dst-nat", "10.0.10.2"},
|
||||
}
|
||||
|
||||
expectErr := []bool{false, false, true}
|
||||
|
||||
for i := range testCases {
|
||||
err := ExecConntrackTool(&fexec, testCases[i]...)
|
||||
|
||||
if expectErr[i] {
|
||||
if err == nil {
|
||||
t.Errorf("expected err, got %v", err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
execCmd := strings.Join(fcmd.CombinedOutputLog[i], " ")
|
||||
expectCmd := fmt.Sprintf("%s %s", "conntrack", strings.Join(testCases[i], " "))
|
||||
|
||||
if execCmd != expectCmd {
|
||||
t.Errorf("expect execute command: %s, but got: %s", expectCmd, execCmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearUDPConntrackForIP(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) {
|
||||
return []byte(""), fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
|
||||
},
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
},
|
||||
}
|
||||
fexec := fakeexec.FakeExec{
|
||||
CommandScript: []fakeexec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ip string
|
||||
}{
|
||||
{"IPv4 success", "10.240.0.3"},
|
||||
{"IPv4 success", "10.240.0.5"},
|
||||
{"IPv4 simulated error", "10.240.0.4"},
|
||||
{"IPv6 success", "2001:db8::10"},
|
||||
}
|
||||
|
||||
svcCount := 0
|
||||
for _, tc := range testCases {
|
||||
if err := ClearUDPConntrackForIP(&fexec, tc.ip); err != nil {
|
||||
t.Errorf("%s test case:, Unexpected error: %v", tc.name, err)
|
||||
}
|
||||
expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s -p udp", tc.ip) + familyParamStr(IsIPv6String(tc.ip))
|
||||
execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ")
|
||||
if expectCommand != execCommand {
|
||||
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
|
||||
}
|
||||
svcCount++
|
||||
}
|
||||
if svcCount != fexec.CommandCalls {
|
||||
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearUDPConntrackForPort(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) {
|
||||
return []byte(""), fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
|
||||
},
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
},
|
||||
}
|
||||
fexec := fakeexec.FakeExec{
|
||||
CommandScript: []fakeexec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
port int
|
||||
isIPv6 bool
|
||||
}{
|
||||
{"IPv4, no error", 8080, false},
|
||||
{"IPv4, simulated error", 9090, false},
|
||||
{"IPv6, no error", 6666, true},
|
||||
}
|
||||
svcCount := 0
|
||||
for _, tc := range testCases {
|
||||
err := ClearUDPConntrackForPort(&fexec, tc.port, tc.isIPv6)
|
||||
if err != nil {
|
||||
t.Errorf("%s test case: Unexpected error: %v", tc.name, err)
|
||||
}
|
||||
expectCommand := fmt.Sprintf("conntrack -D -p udp --dport %d", tc.port) + familyParamStr(tc.isIPv6)
|
||||
execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ")
|
||||
if expectCommand != execCommand {
|
||||
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
|
||||
}
|
||||
svcCount++
|
||||
}
|
||||
if svcCount != fexec.CommandCalls {
|
||||
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteUDPConnections(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
func() ([]byte, error) {
|
||||
return []byte(""), fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
|
||||
},
|
||||
func() ([]byte, error) { return []byte("1 flow entries have been deleted"), nil },
|
||||
},
|
||||
}
|
||||
fexec := fakeexec.FakeExec{
|
||||
CommandScript: []fakeexec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
origin string
|
||||
dest string
|
||||
}{
|
||||
{
|
||||
name: "IPv4 success",
|
||||
origin: "1.2.3.4",
|
||||
dest: "10.20.30.40",
|
||||
},
|
||||
{
|
||||
name: "IPv4 simulated failure",
|
||||
origin: "2.3.4.5",
|
||||
dest: "20.30.40.50",
|
||||
},
|
||||
{
|
||||
name: "IPv6 success",
|
||||
origin: "fd00::600d:f00d",
|
||||
dest: "2001:db8::5",
|
||||
},
|
||||
}
|
||||
svcCount := 0
|
||||
for i, tc := range testCases {
|
||||
err := ClearUDPConntrackForPeers(&fexec, tc.origin, tc.dest)
|
||||
if err != nil {
|
||||
t.Errorf("%s test case: unexpected error: %v", tc.name, err)
|
||||
}
|
||||
expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.origin, tc.dest) + familyParamStr(IsIPv6String(tc.origin))
|
||||
execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ")
|
||||
if expectCommand != execCommand {
|
||||
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
|
||||
}
|
||||
svcCount++
|
||||
}
|
||||
if svcCount != fexec.CommandCalls {
|
||||
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsIPv6String(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ip string
|
||||
expectIPv6 bool
|
||||
}{
|
||||
{
|
||||
ip: "127.0.0.1",
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: "192.168.0.0",
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: "1.2.3.4",
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: "bad ip",
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: "::1",
|
||||
expectIPv6: true,
|
||||
},
|
||||
{
|
||||
ip: "fd00::600d:f00d",
|
||||
expectIPv6: true,
|
||||
},
|
||||
{
|
||||
ip: "2001:db8::5",
|
||||
expectIPv6: true,
|
||||
},
|
||||
}
|
||||
for i := range testCases {
|
||||
isIPv6 := IsIPv6String(testCases[i].ip)
|
||||
if isIPv6 != testCases[i].expectIPv6 {
|
||||
t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsIPv6(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ip net.IP
|
||||
expectIPv6 bool
|
||||
}{
|
||||
{
|
||||
ip: net.IPv4zero,
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: net.IPv4bcast,
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("127.0.0.1"),
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("10.20.40.40"),
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("172.17.3.0"),
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: nil,
|
||||
expectIPv6: false,
|
||||
},
|
||||
{
|
||||
ip: net.IPv6loopback,
|
||||
expectIPv6: true,
|
||||
},
|
||||
{
|
||||
ip: net.IPv6zero,
|
||||
expectIPv6: true,
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("fd00::600d:f00d"),
|
||||
expectIPv6: true,
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("2001:db8::5"),
|
||||
expectIPv6: true,
|
||||
},
|
||||
}
|
||||
for i := range testCases {
|
||||
isIPv6 := IsIPv6(testCases[i].ip)
|
||||
if isIPv6 != testCases[i].expectIPv6 {
|
||||
t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6)
|
||||
}
|
||||
}
|
||||
}
|
1
vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go
generated
vendored
@ -47,6 +47,7 @@ func IPPart(s string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// PortPart returns just the port part of an endpoint string.
|
||||
func PortPart(s string) (int, error) {
|
||||
// Must be IP:port
|
||||
_, port, err := net.SplitHostPort(s)
|
||||
|
45
vendor/k8s.io/kubernetes/pkg/proxy/util/network.go
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/pkg/proxy/util/network.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// NetworkInterfacer defines an interface for several net library functions. Production
|
||||
// code will forward to net library functions, and unit tests will override the methods
|
||||
// for testing purposes.
|
||||
type NetworkInterfacer interface {
|
||||
Addrs(intf *net.Interface) ([]net.Addr, error)
|
||||
Interfaces() ([]net.Interface, error)
|
||||
}
|
||||
|
||||
// RealNetwork implements the NetworkInterfacer interface for production code, just
|
||||
// wrapping the underlying net library function calls.
|
||||
type RealNetwork struct{}
|
||||
|
||||
// Addrs wraps net.Interface.Addrs(), it's a part of NetworkInterfacer interface.
|
||||
func (_ RealNetwork) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||
return intf.Addrs()
|
||||
}
|
||||
|
||||
// Interfaces wraps net.Interfaces(), it's a part of NetworkInterfacer interface.
|
||||
func (_ RealNetwork) Interfaces() ([]net.Interface, error) {
|
||||
return net.Interfaces()
|
||||
}
|
||||
|
||||
var _ NetworkInterfacer = &RealNetwork{}
|
22
vendor/k8s.io/kubernetes/pkg/proxy/util/testing/BUILD
generated
vendored
Normal file
22
vendor/k8s.io/kubernetes/pkg/proxy/util/testing/BUILD
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/util/testing",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
65
vendor/k8s.io/kubernetes/pkg/proxy/util/testing/fake.go
generated
vendored
Normal file
65
vendor/k8s.io/kubernetes/pkg/proxy/util/testing/fake.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import "net"
|
||||
|
||||
// FakeNetwork implements the NetworkInterfacer interface for test purpose.
|
||||
type FakeNetwork struct {
|
||||
NetworkInterfaces []net.Interface
|
||||
// The key of map Addrs is the network interface name
|
||||
Address map[string][]net.Addr
|
||||
}
|
||||
|
||||
// NewFakeNetwork initializes a FakeNetwork.
|
||||
func NewFakeNetwork() *FakeNetwork {
|
||||
return &FakeNetwork{
|
||||
NetworkInterfaces: make([]net.Interface, 0),
|
||||
Address: make(map[string][]net.Addr),
|
||||
}
|
||||
}
|
||||
|
||||
// AddInterfaceAddr create an interface and its associated addresses for FakeNetwork implementation.
|
||||
func (f *FakeNetwork) AddInterfaceAddr(intf *net.Interface, addrs []net.Addr) {
|
||||
f.NetworkInterfaces = append(f.NetworkInterfaces, *intf)
|
||||
f.Address[intf.Name] = addrs
|
||||
}
|
||||
|
||||
// Addrs is part of NetworkInterfacer interface.
|
||||
func (f *FakeNetwork) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||
return f.Address[intf.Name], nil
|
||||
}
|
||||
|
||||
// Interfaces is part of NetworkInterfacer interface.
|
||||
func (f *FakeNetwork) Interfaces() ([]net.Interface, error) {
|
||||
return f.NetworkInterfaces, nil
|
||||
}
|
||||
|
||||
// AddrStruct implements the net.Addr for test purpose.
|
||||
type AddrStruct struct{ Val string }
|
||||
|
||||
// Network is part of net.Addr interface.
|
||||
func (a AddrStruct) Network() string {
|
||||
return a.Val
|
||||
}
|
||||
|
||||
// String is part of net.Addr interface.
|
||||
func (a AddrStruct) String() string {
|
||||
return a.Val
|
||||
}
|
||||
|
||||
var _ net.Addr = &AddrStruct{}
|
90
vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go
generated
vendored
90
vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go
generated
vendored
@ -17,15 +17,32 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/record"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
IPv4ZeroCIDR = "0.0.0.0/0"
|
||||
IPv6ZeroCIDR = "::/0"
|
||||
)
|
||||
|
||||
func IsZeroCIDR(cidr string) bool {
|
||||
if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsLocalIP(ip string) (bool, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
@ -56,3 +73,76 @@ func ShouldSkipService(svcName types.NamespacedName, service *api.Service) bool
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetNodeAddresses return all matched node IP addresses based on given cidr slice.
|
||||
// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
|
||||
// NetworkInterfacer is injected for test purpose.
|
||||
// We expect the cidrs passed in is already validated.
|
||||
// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
|
||||
// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
|
||||
// only return `0.0.0.0/0`.
|
||||
// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
|
||||
func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
|
||||
uniqueAddressList := sets.NewString()
|
||||
if len(cidrs) == 0 {
|
||||
uniqueAddressList.Insert(IPv4ZeroCIDR)
|
||||
uniqueAddressList.Insert(IPv6ZeroCIDR)
|
||||
return uniqueAddressList, nil
|
||||
}
|
||||
// First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
|
||||
for _, cidr := range cidrs {
|
||||
if IsZeroCIDR(cidr) {
|
||||
uniqueAddressList.Insert(cidr)
|
||||
}
|
||||
}
|
||||
// Second round of iteration to parse IPs based on cidr.
|
||||
for _, cidr := range cidrs {
|
||||
if IsZeroCIDR(cidr) {
|
||||
continue
|
||||
}
|
||||
_, ipNet, _ := net.ParseCIDR(cidr)
|
||||
itfs, err := nw.Interfaces()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing all interfaces from host, error: %v", err)
|
||||
}
|
||||
for _, itf := range itfs {
|
||||
addrs, err := nw.Addrs(&itf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting address from interface %s, error: %v", itf.Name, err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
ip, _, err := net.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing CIDR for interface %s, error: %v", itf.Name, err)
|
||||
}
|
||||
if ipNet.Contains(ip) {
|
||||
if utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
|
||||
uniqueAddressList.Insert(ip.String())
|
||||
}
|
||||
if !utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
|
||||
uniqueAddressList.Insert(ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return uniqueAddressList, nil
|
||||
}
|
||||
|
||||
// LogAndEmitIncorrectIPVersionEvent logs and emits incorrect IP version event.
|
||||
func LogAndEmitIncorrectIPVersionEvent(recorder record.EventRecorder, fieldName, fieldValue, svcNamespace, svcName string, svcUID types.UID) {
|
||||
errMsg := fmt.Sprintf("%s in %s has incorrect IP version", fieldValue, fieldName)
|
||||
glog.Errorf("%s (service %s/%s).", errMsg, svcNamespace, svcName)
|
||||
if recorder != nil {
|
||||
recorder.Eventf(
|
||||
&v1.ObjectReference{
|
||||
Kind: "Service",
|
||||
Name: svcName,
|
||||
Namespace: svcNamespace,
|
||||
UID: svcUID,
|
||||
}, v1.EventTypeWarning, "KubeProxyIncorrectIPVersion", errMsg)
|
||||
}
|
||||
}
|
||||
|
218
vendor/k8s.io/kubernetes/pkg/proxy/util/utils_test.go
generated
vendored
218
vendor/k8s.io/kubernetes/pkg/proxy/util/utils_test.go
generated
vendored
@ -17,11 +17,14 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
fake "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||
)
|
||||
|
||||
func TestShouldSkipService(t *testing.T) {
|
||||
@ -109,3 +112,218 @@ func TestShouldSkipService(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type InterfaceAddrsPair struct {
|
||||
itf net.Interface
|
||||
addrs []net.Addr
|
||||
}
|
||||
|
||||
func TestGetNodeAddressses(t *testing.T) {
|
||||
testCases := []struct {
|
||||
cidrs []string
|
||||
nw *fake.FakeNetwork
|
||||
itfAddrsPairs []InterfaceAddrsPair
|
||||
expected sets.String
|
||||
}{
|
||||
{ // case 0
|
||||
cidrs: []string{"10.20.30.0/24"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "100.200.201.1/24"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("10.20.30.51"),
|
||||
},
|
||||
{ // case 1
|
||||
cidrs: []string{"0.0.0.0/0"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("0.0.0.0/0"),
|
||||
},
|
||||
{ // case 2
|
||||
cidrs: []string{"2001:db8::/32", "::1/128"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("2001:db8::1", "::1"),
|
||||
},
|
||||
{ // case 3
|
||||
cidrs: []string{"::/0"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("::/0"),
|
||||
},
|
||||
{ // case 4
|
||||
cidrs: []string{"127.0.0.1/32"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("127.0.0.1"),
|
||||
},
|
||||
{ // case 5
|
||||
cidrs: []string{"127.0.0.0/8"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.1.1/8"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("127.0.1.1"),
|
||||
},
|
||||
{ // case 6
|
||||
cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "100.200.201.1/24"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("10.20.30.51", "100.200.201.1"),
|
||||
},
|
||||
{ // case 7
|
||||
cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "192.168.1.2/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString(),
|
||||
},
|
||||
{ // case 8
|
||||
cidrs: []string{},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "192.168.1.2/24"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("0.0.0.0/0", "::/0"),
|
||||
},
|
||||
{ // case 9
|
||||
cidrs: []string{},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("0.0.0.0/0", "::/0"),
|
||||
},
|
||||
{ // case 9
|
||||
cidrs: []string{"1.2.3.0/24", "0.0.0.0/0"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("0.0.0.0/0"),
|
||||
},
|
||||
{ // case 10
|
||||
cidrs: []string{"0.0.0.0/0", "1.2.3.0/24", "::1/128"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("0.0.0.0/0", "::1"),
|
||||
},
|
||||
{ // case 11
|
||||
cidrs: []string{"::/0", "1.2.3.0/24", "::1/128"},
|
||||
nw: fake.NewFakeNetwork(),
|
||||
itfAddrsPairs: []InterfaceAddrsPair{
|
||||
{
|
||||
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||
},
|
||||
{
|
||||
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||
},
|
||||
},
|
||||
expected: sets.NewString("::/0", "1.2.3.4"),
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
for _, pair := range testCases[i].itfAddrsPairs {
|
||||
testCases[i].nw.AddInterfaceAddr(&pair.itf, pair.addrs)
|
||||
}
|
||||
addrList, err := GetNodeAddresses(testCases[i].cidrs, testCases[i].nw)
|
||||
if err != nil {
|
||||
t.Errorf("case [%d], unexpected error: %v", i, err)
|
||||
}
|
||||
if !addrList.Equal(testCases[i].expected) {
|
||||
t.Errorf("case [%d], unexpected mismatch, expected: %v, got: %v", i, testCases[i].expected, addrList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/BUILD
generated
vendored
@ -1,11 +1,11 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"metrics.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"proxier.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
@ -15,11 +15,10 @@ go_library(
|
||||
deps = [
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/healthcheck:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
@ -29,40 +28,12 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"proxier_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/winkernel",
|
||||
library = ":go_default_library",
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/util/async:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec/testing:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/proxier.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/proxier.go
generated
vendored
@ -35,12 +35,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/record"
|
||||
apiservice "k8s.io/kubernetes/pkg/api/service"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||
"k8s.io/kubernetes/pkg/util/async"
|
||||
@ -160,8 +158,7 @@ func (ep *endpointsInfo) Cleanup() {
|
||||
// returns a new serviceInfo struct
|
||||
func newServiceInfo(svcPortName proxy.ServicePortName, port *api.ServicePort, service *api.Service) *serviceInfo {
|
||||
onlyNodeLocalEndpoints := false
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ExternalTrafficLocalOnly) &&
|
||||
apiservice.RequestsOnlyLocalTraffic(service) {
|
||||
if apiservice.RequestsOnlyLocalTraffic(service) {
|
||||
onlyNodeLocalEndpoints = true
|
||||
}
|
||||
|
||||
@ -474,7 +471,7 @@ func NewProxier(
|
||||
}
|
||||
hnsNetwork, err := getHnsNetworkInfo(hnsNetworkName)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to find Hns Network speficied by %s. Please check environment variable KUBE_NETWORK", hnsNetworkName)
|
||||
glog.Fatalf("Unable to find Hns Network specified by %s. Please check environment variable KUBE_NETWORK", hnsNetworkName)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -825,10 +822,6 @@ func (proxier *Proxier) updateEndpointsMap() (result updateEndpointMapResult) {
|
||||
changes.items = make(map[types.NamespacedName]*endpointsChange)
|
||||
}()
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ExternalTrafficLocalOnly) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: If this will appear to be computationally expensive, consider
|
||||
// computing this incrementally similarly to endpointsMap.
|
||||
result.hcEndpoints = make(map[types.NamespacedName]int)
|
||||
|
2031
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/proxier_test.go
generated
vendored
2031
vendor/k8s.io/kubernetes/pkg/proxy/winkernel/proxier_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
3
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/BUILD
generated
vendored
@ -39,8 +39,7 @@ go_test(
|
||||
"proxier_test.go",
|
||||
"roundrobin_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/proxy/winuserspace",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
|
9
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/proxier.go
generated
vendored
9
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/proxier.go
generated
vendored
@ -19,6 +19,7 @@ package winuserspace
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@ -103,7 +104,7 @@ type portMapKey struct {
|
||||
}
|
||||
|
||||
func (k *portMapKey) String() string {
|
||||
return fmt.Sprintf("%s:%d/%s", k.ip, k.port, k.protocol)
|
||||
return fmt.Sprintf("%s/%s", net.JoinHostPort(k.ip, strconv.Itoa(k.port)), k.protocol)
|
||||
}
|
||||
|
||||
// A value for the portMap
|
||||
@ -233,7 +234,7 @@ func (proxier *Proxier) addServicePortPortal(servicePortPortalName ServicePortPo
|
||||
if existed, err := proxier.netsh.EnsureIPAddress(args, serviceIP); err != nil {
|
||||
return nil, err
|
||||
} else if !existed {
|
||||
glog.V(3).Infof("Added ip address to fowarder interface for service %q at %s:%d/%s", servicePortPortalName, listenIP, port, protocol)
|
||||
glog.V(3).Infof("Added ip address to fowarder interface for service %q at %s/%s", servicePortPortalName, net.JoinHostPort(listenIP, strconv.Itoa(port)), protocol)
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +259,7 @@ func (proxier *Proxier) addServicePortPortal(servicePortPortalName ServicePortPo
|
||||
}
|
||||
proxier.setServiceInfo(servicePortPortalName, si)
|
||||
|
||||
glog.V(2).Infof("Proxying for service %q at %s:%d/%s", servicePortPortalName, listenIP, port, protocol)
|
||||
glog.V(2).Infof("Proxying for service %q at %s/%s", servicePortPortalName, net.JoinHostPort(listenIP, strconv.Itoa(port)), protocol)
|
||||
go func(service ServicePortPortalName, proxier *Proxier) {
|
||||
defer runtime.HandleCrash()
|
||||
atomic.AddInt32(&proxier.numProxyLoops, 1)
|
||||
@ -341,7 +342,7 @@ func (proxier *Proxier) mergeService(service *api.Service) map[ServicePortPortal
|
||||
glog.Errorf("Failed to close service port portal %q: %v", servicePortPortalName, err)
|
||||
}
|
||||
}
|
||||
glog.V(1).Infof("Adding new service %q at %s:%d/%s", servicePortPortalName, listenIP, listenPort, protocol)
|
||||
glog.V(1).Infof("Adding new service %q at %s/%s", servicePortPortalName, net.JoinHostPort(listenIP, strconv.Itoa(listenPort)), protocol)
|
||||
info, err := proxier.addServicePortPortal(servicePortPortalName, protocol, listenIP, listenPort, proxier.udpIdleTimeout)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to start proxy for %q: %v", servicePortPortalName, err)
|
||||
|
4
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/proxysocket.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/proxy/winuserspace/proxysocket.go
generated
vendored
@ -382,7 +382,7 @@ func processUnpackedDNSResponsePacket(
|
||||
if found {
|
||||
index := atomic.SwapInt32(&state.searchIndex, state.searchIndex+1)
|
||||
if rcode != 0 && index >= 0 && index < int32(len(dnsSearch)) {
|
||||
// If the reponse has failure and iteration through the search list has not
|
||||
// If the response has failure and iteration through the search list has not
|
||||
// reached the end, retry on behalf of the client using the original query message
|
||||
drop = true
|
||||
length, err = appendDNSSuffix(state.msg, buffer, length, dnsSearch[index])
|
||||
@ -477,7 +477,7 @@ func processDNSResponsePacket(
|
||||
|
||||
// QDCOUNT
|
||||
if len(msg.Question) != 1 {
|
||||
glog.V(1).Infof("Number of entries in the reponse section of the DNS packet is: %d", len(msg.Answer))
|
||||
glog.V(1).Infof("Number of entries in the response section of the DNS packet is: %d", len(msg.Answer))
|
||||
return drop, length, nil
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user