From 936a11e775e0dbafef8ce4a1f5598663890ad7ad Mon Sep 17 00:00:00 2001 From: Harry Zhang Date: Wed, 6 Jan 2016 23:56:41 +0800 Subject: [PATCH] Use networking to hold network related pkgs Change names of unclear methods Use net as pkg name for short --- cmd/integration/integration.go | 3 +- cmd/kube-apiserver/app/options/options.go | 3 +- cmd/kube-apiserver/app/server.go | 6 +- cmd/kube-proxy/app/options/options.go | 4 +- pkg/apiserver/apiserver.go | 3 +- pkg/apiserver/proxy.go | 4 +- pkg/apiserver/validator.go | 4 +- pkg/client/chaosclient/chaosclient.go | 4 +- pkg/client/unversioned/request.go | 4 +- pkg/client/unversioned/services.go | 4 +- pkg/cloudprovider/providers/mesos/client.go | 4 +- pkg/genericapiserver/genericapiserver.go | 9 +- pkg/genericapiserver/genericapiserver_test.go | 4 +- pkg/kubelet/client/kubelet_client.go | 4 +- pkg/kubelet/kubelet.go | 3 +- pkg/master/controller.go | 6 +- pkg/master/master_test.go | 7 +- pkg/proxy/userspace/port_allocator.go | 7 +- pkg/proxy/userspace/port_allocator_test.go | 8 +- pkg/proxy/userspace/proxier.go | 8 +- pkg/registry/generic/rest/proxy.go | 4 +- pkg/registry/node/strategy.go | 4 +- pkg/registry/pod/strategy.go | 4 +- .../service/portallocator/allocator.go | 12 +- .../service/portallocator/allocator_test.go | 10 +- .../portallocator/controller/repair.go | 5 +- pkg/registry/service/rest.go | 4 +- pkg/registry/service/rest_test.go | 5 +- pkg/util/{ => net}/http.go | 13 +- pkg/util/net/interface.go | 278 ++++++++++++++++ pkg/util/net/interface_test.go | 300 ++++++++++++++++++ pkg/util/{ => net}/port_range.go | 2 +- pkg/util/{ => net}/port_range_test.go | 2 +- pkg/util/{ => net}/port_split.go | 2 +- pkg/util/{ => net}/port_split_test.go | 2 +- pkg/util/proxy/dial.go | 6 +- pkg/util/proxy/transport.go | 4 +- pkg/util/util.go | 262 --------------- pkg/util/util_test.go | 278 ---------------- pkg/watch/iowatcher.go | 3 +- .../pkg/auth/authenticator/token/oidc/oidc.go | 3 +- test/e2e/proxy.go | 8 +- test/e2e/service.go | 3 +- 43 files changed, 687 insertions(+), 626 deletions(-) rename pkg/util/{ => net}/http.go (92%) create mode 100644 pkg/util/net/interface.go create mode 100644 pkg/util/net/interface_test.go rename pkg/util/{ => net}/port_range.go (99%) rename pkg/util/{ => net}/port_range_test.go (99%) rename pkg/util/{ => net}/port_split.go (99%) rename pkg/util/{ => net}/port_split_test.go (99%) diff --git a/cmd/integration/integration.go b/cmd/integration/integration.go index ca5804a675..2539c71753 100644 --- a/cmd/integration/integration.go +++ b/cmd/integration/integration.go @@ -53,6 +53,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/master" "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/volume/empty_dir" @@ -153,7 +154,7 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string } // The caller of master.New should guarantee pulicAddress is properly set - hostIP, err := util.ValidPublicAddrForMaster(publicAddress) + hostIP, err := utilnet.ChooseBindAddress(publicAddress) if err != nil { glog.Fatalf("Unable to find suitable network address.error='%v' . "+ "Fail to get a valid public address for master.", err) diff --git a/cmd/kube-apiserver/app/options/options.go b/cmd/kube-apiserver/app/options/options.go index 09a97ebb34..84d03342fd 100644 --- a/cmd/kube-apiserver/app/options/options.go +++ b/cmd/kube-apiserver/app/options/options.go @@ -31,6 +31,7 @@ import ( kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "github.com/spf13/pflag" ) @@ -76,7 +77,7 @@ type APIServer struct { ServiceAccountKeyFile string ServiceAccountLookup bool ServiceClusterIPRange net.IPNet // TODO: make this a list - ServiceNodePortRange util.PortRange + ServiceNodePortRange utilnet.PortRange StorageVersions string TokenAuthFile string } diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 8232b78ca4..50f1d7bca3 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -51,7 +51,7 @@ import ( "k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/storage" etcdstorage "k8s.io/kubernetes/pkg/storage/etcd" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" ) // NewAPIServerCommand creates a *cobra.Command object with default parameters @@ -164,9 +164,9 @@ func Run(s *options.APIServer) error { // If advertise-address is not specified, use bind-address. If bind-address // is not usable (unset, 0.0.0.0, or loopback), we will use the host's default - // interface as valid public addr for master (see: util#ValidPublicAddrForMaster) + // interface as valid public addr for master (see: util/net#ValidPublicAddrForMaster) if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() { - hostIP, err := util.ValidPublicAddrForMaster(s.BindAddress) + hostIP, err := utilnet.ChooseBindAddress(s.BindAddress) if err != nil { glog.Fatalf("Unable to find suitable network address.error='%v' . "+ "Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err) diff --git a/cmd/kube-proxy/app/options/options.go b/cmd/kube-proxy/app/options/options.go index eaf289b0b6..aaba398ae2 100644 --- a/cmd/kube-proxy/app/options/options.go +++ b/cmd/kube-proxy/app/options/options.go @@ -24,7 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/kubelet/qos" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "github.com/spf13/pflag" ) @@ -42,7 +42,7 @@ type ProxyServerConfig struct { ResourceContainer string Master string Kubeconfig string - PortRange util.PortRange + PortRange utilnet.PortRange HostnameOverride string ProxyMode string IptablesSyncPeriod time.Duration diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index f4f24090ee..75fecacfd3 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -43,6 +43,7 @@ import ( "k8s.io/kubernetes/pkg/util" utilerrors "k8s.io/kubernetes/pkg/util/errors" "k8s.io/kubernetes/pkg/util/flushwriter" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/wsstream" "k8s.io/kubernetes/pkg/version" @@ -61,7 +62,7 @@ func monitorFilter(action, resource string) restful.FilterFunction { reqStart := time.Now() chain.ProcessFilter(req, res) httpCode := res.StatusCode() - metrics.Monitor(&action, &resource, util.GetClient(req.Request), &httpCode, reqStart) + metrics.Monitor(&action, &resource, utilnet.GetHTTPClient(req.Request), &httpCode, reqStart) } } diff --git a/pkg/apiserver/proxy.go b/pkg/apiserver/proxy.go index df88d726da..32474daaa9 100644 --- a/pkg/apiserver/proxy.go +++ b/pkg/apiserver/proxy.go @@ -32,8 +32,8 @@ import ( "k8s.io/kubernetes/pkg/apiserver/metrics" "k8s.io/kubernetes/pkg/httplog" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/httpstream" + "k8s.io/kubernetes/pkg/util/net" proxyutil "k8s.io/kubernetes/pkg/util/proxy" "github.com/golang/glog" @@ -56,7 +56,7 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { var apiResource string var httpCode int reqStart := time.Now() - defer metrics.Monitor(&verb, &apiResource, util.GetClient(req), &httpCode, reqStart) + defer metrics.Monitor(&verb, &apiResource, net.GetHTTPClient(req), &httpCode, reqStart) requestInfo, err := r.requestInfoResolver.GetRequestInfo(req) if err != nil || !requestInfo.IsResourceRequest { diff --git a/pkg/apiserver/validator.go b/pkg/apiserver/validator.go index ded2eca6ba..6474d37a0d 100644 --- a/pkg/apiserver/validator.go +++ b/pkg/apiserver/validator.go @@ -21,7 +21,7 @@ import ( "k8s.io/kubernetes/pkg/probe" httpprober "k8s.io/kubernetes/pkg/probe/http" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "time" ) @@ -57,7 +57,7 @@ func (server *Server) DoServerCheck(prober httpprober.HTTPProber) (probe.Result, if server.EnableHTTPS { scheme = "https" } - url := util.FormatURL(scheme, server.Addr, server.Port, server.Path) + url := utilnet.FormatURL(scheme, server.Addr, server.Port, server.Path) result, data, err := prober.Probe(url, probeTimeOut) diff --git a/pkg/client/chaosclient/chaosclient.go b/pkg/client/chaosclient/chaosclient.go index b74ee80a34..a0ed4b4c15 100644 --- a/pkg/client/chaosclient/chaosclient.go +++ b/pkg/client/chaosclient/chaosclient.go @@ -29,7 +29,7 @@ import ( "reflect" "runtime" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) // chaosrt provides the ability to perform simulations of HTTP client failures @@ -88,7 +88,7 @@ func (rt *chaosrt) RoundTrip(req *http.Request) (*http.Response, error) { return rt.rt.RoundTrip(req) } -var _ = util.RoundTripperWrapper(&chaosrt{}) +var _ = net.RoundTripperWrapper(&chaosrt{}) func (rt *chaosrt) WrappedRoundTripper() http.RoundTripper { return rt.rt diff --git a/pkg/client/unversioned/request.go b/pkg/client/unversioned/request.go index 29cc6f7b49..3c32b89fbf 100644 --- a/pkg/client/unversioned/request.go +++ b/pkg/client/unversioned/request.go @@ -40,7 +40,7 @@ import ( "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/watch" watchjson "k8s.io/kubernetes/pkg/watch/json" @@ -637,7 +637,7 @@ func (r *Request) Watch() (watch.Interface, error) { if err != nil { // The watch stream mechanism handles many common partial data errors, so closed // connections can be retried in many cases. - if util.IsProbableEOF(err) { + if net.IsProbableEOF(err) { return watch.NewEmptyWatch(), nil } return nil, err diff --git a/pkg/client/unversioned/services.go b/pkg/client/unversioned/services.go index 45ef56ad95..e19c493995 100644 --- a/pkg/client/unversioned/services.go +++ b/pkg/client/unversioned/services.go @@ -18,7 +18,7 @@ package unversioned import ( "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/watch" ) @@ -103,7 +103,7 @@ func (c *services) ProxyGet(scheme, name, port, path string, params map[string]s Prefix("proxy"). Namespace(c.ns). Resource("services"). - Name(util.JoinSchemeNamePort(scheme, name, port)). + Name(net.JoinSchemeNamePort(scheme, name, port)). Suffix(path) for k, v := range params { request = request.Param(k, v) diff --git a/pkg/cloudprovider/providers/mesos/client.go b/pkg/cloudprovider/providers/mesos/client.go index 4af49f8ed4..1b488bc62d 100644 --- a/pkg/cloudprovider/providers/mesos/client.go +++ b/pkg/cloudprovider/providers/mesos/client.go @@ -33,7 +33,7 @@ import ( "golang.org/x/net/context" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" ) const defaultClusterName = "mesos" @@ -111,7 +111,7 @@ func newMesosClient( md detector.Master, mesosHttpClientTimeout, stateCacheTTL time.Duration) (*mesosClient, error) { - tr := util.SetTransportDefaults(&http.Transport{}) + tr := utilnet.SetTransportDefaults(&http.Transport{}) httpClient := &http.Client{ Transport: tr, Timeout: mesosHttpClientTimeout, diff --git a/pkg/genericapiserver/genericapiserver.go b/pkg/genericapiserver/genericapiserver.go index 35c7dfda22..88c40bc040 100644 --- a/pkg/genericapiserver/genericapiserver.go +++ b/pkg/genericapiserver/genericapiserver.go @@ -43,6 +43,7 @@ import ( "k8s.io/kubernetes/pkg/storage" "k8s.io/kubernetes/pkg/ui" "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" systemd "github.com/coreos/go-systemd/daemon" @@ -212,7 +213,7 @@ type Config struct { ServiceReadWriteIP net.IP // The range of ports to be assigned to services with type=NodePort or greater - ServiceNodePortRange util.PortRange + ServiceNodePortRange utilnet.PortRange // Used to customize default proxy dial/tls options ProxyDialer apiserver.ProxyDialerFunc @@ -237,7 +238,7 @@ type Config struct { type GenericAPIServer struct { // "Inputs", Copied from Config ServiceClusterIPRange *net.IPNet - ServiceNodePortRange util.PortRange + ServiceNodePortRange utilnet.PortRange cacheTimeout time.Duration MinRequestTimeout time.Duration @@ -319,7 +320,7 @@ func setDefaults(c *Config) { // We should probably allow this for clouds that don't require NodePort to do load-balancing (GCE) // but then that breaks the strict nestedness of ServiceType. // Review post-v1 - defaultServiceNodePortRange := util.PortRange{Base: 30000, Size: 2768} + defaultServiceNodePortRange := utilnet.PortRange{Base: 30000, Size: 2768} c.ServiceNodePortRange = defaultServiceNodePortRange glog.Infof("Node port range unspecified. Defaulting to %v.", c.ServiceNodePortRange) } @@ -454,7 +455,7 @@ func NewHandlerContainer(mux *http.ServeMux) *restful.Container { func (s *GenericAPIServer) init(c *Config) { if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil { - s.ProxyTransport = util.SetTransportDefaults(&http.Transport{ + s.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{ Dial: c.ProxyDialer, TLSClientConfig: c.ProxyTLSClientConfig, }) diff --git a/pkg/genericapiserver/genericapiserver_test.go b/pkg/genericapiserver/genericapiserver_test.go index a2aa8de1bd..d07ed8875b 100644 --- a/pkg/genericapiserver/genericapiserver_test.go +++ b/pkg/genericapiserver/genericapiserver_test.go @@ -30,7 +30,7 @@ import ( "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apiserver" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "github.com/stretchr/testify/assert" ) @@ -77,7 +77,7 @@ func TestNew(t *testing.T) { assert.Equal(s.ServiceReadWriteIP, config.ServiceReadWriteIP) // These functions should point to the same memory location - serverDialer, _ := util.Dialer(s.ProxyTransport) + serverDialer, _ := utilnet.Dialer(s.ProxyTransport) serverDialerFunc := fmt.Sprintf("%p", serverDialer) configDialerFunc := fmt.Sprintf("%p", config.ProxyDialer) assert.Equal(serverDialerFunc, configDialerFunc) diff --git a/pkg/kubelet/client/kubelet_client.go b/pkg/kubelet/client/kubelet_client.go index cba2366875..3d547726a9 100644 --- a/pkg/kubelet/client/kubelet_client.go +++ b/pkg/kubelet/client/kubelet_client.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/client/transport" client "k8s.io/kubernetes/pkg/client/unversioned" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" ) type KubeletClientConfig struct { @@ -71,7 +71,7 @@ func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) { rt := http.DefaultTransport if config.Dial != nil || tlsConfig != nil { - rt = util.SetTransportDefaults(&http.Transport{ + rt = utilnet.SetTransportDefaults(&http.Transport{ Dial: config.Dial, TLSClientConfig: tlsConfig, }) diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 0f745744ea..77d1a3129c 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -73,6 +73,7 @@ import ( utilerrors "k8s.io/kubernetes/pkg/util/errors" kubeio "k8s.io/kubernetes/pkg/util/io" "k8s.io/kubernetes/pkg/util/mount" + utilnet "k8s.io/kubernetes/pkg/util/net" nodeutil "k8s.io/kubernetes/pkg/util/node" "k8s.io/kubernetes/pkg/util/oom" "k8s.io/kubernetes/pkg/util/procfs" @@ -2677,7 +2678,7 @@ func (kl *Kubelet) setNodeAddress(node *api.Node) error { } if len(node.Status.Addresses) == 0 { - ip, err := util.ChooseHostInterface() + ip, err := utilnet.ChooseHostInterface() if err != nil { return err } diff --git a/pkg/master/controller.go b/pkg/master/controller.go index fe1202eebf..41071cf4b2 100644 --- a/pkg/master/controller.go +++ b/pkg/master/controller.go @@ -21,6 +21,7 @@ import ( "net" "time" + "github.com/golang/glog" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/endpoints" "k8s.io/kubernetes/pkg/api/errors" @@ -32,8 +33,7 @@ import ( portallocatorcontroller "k8s.io/kubernetes/pkg/registry/service/portallocator/controller" "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/intstr" - - "github.com/golang/glog" + utilnet "k8s.io/kubernetes/pkg/util/net" ) // Controller is the controller manager for the core bootstrap Kubernetes controller @@ -51,7 +51,7 @@ type Controller struct { ServiceNodePortRegistry service.RangeRegistry ServiceNodePortInterval time.Duration - ServiceNodePortRange util.PortRange + ServiceNodePortRange utilnet.PortRange EndpointRegistry endpoint.Registry EndpointInterval time.Duration diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 38da80c594..9147f95128 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -33,6 +33,8 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/unversioned" apiutil "k8s.io/kubernetes/pkg/api/util" + utilnet "k8s.io/kubernetes/pkg/util/net" + "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/kubelet/client" @@ -44,7 +46,6 @@ import ( etcdstorage "k8s.io/kubernetes/pkg/storage/etcd" "k8s.io/kubernetes/pkg/storage/etcd/etcdtest" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" - "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/intstr" "github.com/emicklei/go-restful" @@ -110,7 +111,7 @@ func TestNew(t *testing.T) { assert.Equal(master.ServiceReadWriteIP, config.ServiceReadWriteIP) // These functions should point to the same memory location - masterDialer, _ := util.Dialer(master.ProxyTransport) + masterDialer, _ := utilnet.Dialer(master.ProxyTransport) masterDialerFunc := fmt.Sprintf("%p", masterDialer) configDialerFunc := fmt.Sprintf("%p", config.ProxyDialer) assert.Equal(masterDialerFunc, configDialerFunc) @@ -164,7 +165,7 @@ func TestNewBootstrapController(t *testing.T) { master, etcdserver, _, assert := setUp(t) defer etcdserver.Terminate(t) - portRange := util.PortRange{Base: 10, Size: 10} + portRange := utilnet.PortRange{Base: 10, Size: 10} master.namespaceRegistry = namespace.NewRegistry(nil) master.serviceRegistry = registrytest.NewServiceRegistry() diff --git a/pkg/proxy/userspace/port_allocator.go b/pkg/proxy/userspace/port_allocator.go index c9fcd7692a..a1ff408ea6 100644 --- a/pkg/proxy/userspace/port_allocator.go +++ b/pkg/proxy/userspace/port_allocator.go @@ -24,6 +24,7 @@ import ( "time" "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) var ( @@ -52,7 +53,7 @@ func (r *randomAllocator) Release(_ int) { // newPortAllocator builds PortAllocator for a given PortRange. If the PortRange is empty // then a random port allocator is returned; otherwise, a new range-based allocator // is returned. -func newPortAllocator(r util.PortRange) PortAllocator { +func newPortAllocator(r net.PortRange) PortAllocator { if r.Base == 0 { return &randomAllocator{} } @@ -66,14 +67,14 @@ const ( ) type rangeAllocator struct { - util.PortRange + net.PortRange ports chan int used big.Int lock sync.Mutex rand *rand.Rand } -func newPortRangeAllocator(r util.PortRange) PortAllocator { +func newPortRangeAllocator(r net.PortRange) PortAllocator { if r.Base == 0 || r.Size == 0 { panic("illegal argument: may not specify an empty port range") } diff --git a/pkg/proxy/userspace/port_allocator_test.go b/pkg/proxy/userspace/port_allocator_test.go index 2573d5f168..b2c2e5a677 100644 --- a/pkg/proxy/userspace/port_allocator_test.go +++ b/pkg/proxy/userspace/port_allocator_test.go @@ -20,11 +20,11 @@ import ( "reflect" "testing" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) func TestRangeAllocatorEmpty(t *testing.T) { - r := &util.PortRange{} + r := &net.PortRange{} r.Set("0-0") defer func() { if rv := recover(); rv == nil { @@ -35,7 +35,7 @@ func TestRangeAllocatorEmpty(t *testing.T) { } func TestRangeAllocatorFullyAllocated(t *testing.T) { - r := &util.PortRange{} + r := &net.PortRange{} r.Set("1-1") a := newPortRangeAllocator(*r) p, err := a.AllocateNext() @@ -67,7 +67,7 @@ func TestRangeAllocatorFullyAllocated(t *testing.T) { } func TestRangeAllocator_RandomishAllocation(t *testing.T) { - r := &util.PortRange{} + r := &net.PortRange{} r.Set("1-100") a := newPortRangeAllocator(*r) diff --git a/pkg/proxy/userspace/proxier.go b/pkg/proxy/userspace/proxier.go index fd3cac07d8..f06210cba3 100644 --- a/pkg/proxy/userspace/proxier.go +++ b/pkg/proxy/userspace/proxier.go @@ -30,6 +30,8 @@ import ( "k8s.io/kubernetes/pkg/proxy" "k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" + utilerrors "k8s.io/kubernetes/pkg/util/errors" "k8s.io/kubernetes/pkg/util/iptables" ) @@ -137,12 +139,12 @@ 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, pr util.PortRange, syncPeriod, udpIdleTimeout time.Duration) (*Proxier, error) { +func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, pr utilnet.PortRange, syncPeriod, udpIdleTimeout time.Duration) (*Proxier, error) { if listenIP.Equal(localhostIPv4) || listenIP.Equal(localhostIPv6) { return nil, ErrProxyOnLocalhost } - hostIP, err := util.ChooseHostInterface() + hostIP, err := utilnet.ChooseHostInterface() if err != nil { return nil, fmt.Errorf("failed to select a host interface: %v", err) } @@ -161,7 +163,7 @@ func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.In func createProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, hostIP net.IP, proxyPorts PortAllocator, syncPeriod, udpIdleTimeout time.Duration) (*Proxier, error) { // convenient to pass nil for tests.. if proxyPorts == nil { - proxyPorts = newPortAllocator(util.PortRange{}) + proxyPorts = newPortAllocator(utilnet.PortRange{}) } // Set up the iptables foundations we need. if err := iptablesInit(iptables); err != nil { diff --git a/pkg/registry/generic/rest/proxy.go b/pkg/registry/generic/rest/proxy.go index 4038ac54f3..ca28831c8c 100644 --- a/pkg/registry/generic/rest/proxy.go +++ b/pkg/registry/generic/rest/proxy.go @@ -26,8 +26,8 @@ import ( "time" "k8s.io/kubernetes/pkg/api/errors" - "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/httpstream" + "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/proxy" "github.com/golang/glog" @@ -226,7 +226,7 @@ func (p *corsRemovingTransport) RoundTrip(req *http.Request) (*http.Response, er return resp, nil } -var _ = util.RoundTripperWrapper(&corsRemovingTransport{}) +var _ = net.RoundTripperWrapper(&corsRemovingTransport{}) func (rt *corsRemovingTransport) WrappedRoundTripper() http.RoundTripper { return rt.RoundTripper diff --git a/pkg/registry/node/strategy.go b/pkg/registry/node/strategy.go index 8f53a155d6..fc00988ba7 100644 --- a/pkg/registry/node/strategy.go +++ b/pkg/registry/node/strategy.go @@ -32,7 +32,7 @@ import ( "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" nodeutil "k8s.io/kubernetes/pkg/util/node" "k8s.io/kubernetes/pkg/util/validation/field" ) @@ -162,7 +162,7 @@ func MatchNode(label labels.Selector, field fields.Selector) generic.Matcher { // ResourceLocation returns an URL and transport which one can use to send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, proxyTransport http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { - schemeReq, name, portReq, valid := util.SplitSchemeNamePort(id) + schemeReq, name, portReq, valid := utilnet.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } diff --git a/pkg/registry/pod/strategy.go b/pkg/registry/pod/strategy.go index f486100da2..4e957fd1eb 100644 --- a/pkg/registry/pod/strategy.go +++ b/pkg/registry/pod/strategy.go @@ -32,7 +32,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/validation/field" ) @@ -199,7 +199,7 @@ func getPod(getter ResourceGetter, ctx api.Context, name string) (*api.Pod, erro func ResourceLocation(getter ResourceGetter, rt http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "podname" or "podname:port" or "scheme:podname:port". // If port is not specified, try to use the first defined port on the pod. - scheme, name, port, valid := util.SplitSchemeNamePort(id) + scheme, name, port, valid := utilnet.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid pod request %q", id)) } diff --git a/pkg/registry/service/portallocator/allocator.go b/pkg/registry/service/portallocator/allocator.go index 75dc837b25..765ac8f3c0 100644 --- a/pkg/registry/service/portallocator/allocator.go +++ b/pkg/registry/service/portallocator/allocator.go @@ -22,7 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/registry/service/allocator" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" "github.com/golang/glog" ) @@ -43,7 +43,7 @@ var ( ) type PortAllocator struct { - portRange util.PortRange + portRange net.PortRange alloc allocator.Interface } @@ -51,8 +51,8 @@ type PortAllocator struct { // PortAllocator implements Interface and Snapshottable var _ Interface = &PortAllocator{} -// NewPortAllocatorCustom creates a PortAllocator over a util.PortRange, calling allocatorFactory to construct the backing store. -func NewPortAllocatorCustom(pr util.PortRange, allocatorFactory allocator.AllocatorFactory) *PortAllocator { +// NewPortAllocatorCustom creates a PortAllocator over a net.PortRange, calling allocatorFactory to construct the backing store. +func NewPortAllocatorCustom(pr net.PortRange, allocatorFactory allocator.AllocatorFactory) *PortAllocator { max := pr.Size rangeSpec := pr.String() @@ -64,7 +64,7 @@ func NewPortAllocatorCustom(pr util.PortRange, allocatorFactory allocator.Alloca } // Helper that wraps NewAllocatorCIDRRange, for creating a range backed by an in-memory store. -func NewPortAllocator(pr util.PortRange) *PortAllocator { +func NewPortAllocator(pr net.PortRange) *PortAllocator { return NewPortAllocatorCustom(pr, func(max int, rangeSpec string) allocator.Interface { return allocator.NewAllocationMap(max, rangeSpec) }) @@ -146,7 +146,7 @@ func (r *PortAllocator) Snapshot(dst *api.RangeAllocation) error { // Restore restores the pool to the previously captured state. ErrMismatchedNetwork // is returned if the provided port range doesn't exactly match the previous range. -func (r *PortAllocator) Restore(pr util.PortRange, data []byte) error { +func (r *PortAllocator) Restore(pr net.PortRange, data []byte) error { if pr.String() != r.portRange.String() { return ErrMismatchedNetwork } diff --git a/pkg/registry/service/portallocator/allocator_test.go b/pkg/registry/service/portallocator/allocator_test.go index dd6d5dd170..38904cb866 100644 --- a/pkg/registry/service/portallocator/allocator_test.go +++ b/pkg/registry/service/portallocator/allocator_test.go @@ -22,12 +22,12 @@ import ( "strconv" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" ) func TestAllocate(t *testing.T) { - pr, err := util.ParsePortRange("10000-10200") + pr, err := net.ParsePortRange("10000-10200") if err != nil { t.Fatal(err) } @@ -97,7 +97,7 @@ func TestAllocate(t *testing.T) { } func TestSnapshot(t *testing.T) { - pr, err := util.ParsePortRange("10000-10200") + pr, err := net.ParsePortRange("10000-10200") if err != nil { t.Fatal(err) } @@ -117,7 +117,7 @@ func TestSnapshot(t *testing.T) { t.Fatal(err) } - pr2, err := util.ParsePortRange(dst.Range) + pr2, err := net.ParsePortRange(dst.Range) if err != nil { t.Fatal(err) } @@ -126,7 +126,7 @@ func TestSnapshot(t *testing.T) { t.Fatalf("mismatched networks: %s : %s", pr, pr2) } - otherPr, err := util.ParsePortRange("200-300") + otherPr, err := net.ParsePortRange("200-300") if err != nil { t.Fatal(err) } diff --git a/pkg/registry/service/portallocator/controller/repair.go b/pkg/registry/service/portallocator/controller/repair.go index c388a8dc95..2f8d255d28 100644 --- a/pkg/registry/service/portallocator/controller/repair.go +++ b/pkg/registry/service/portallocator/controller/repair.go @@ -24,19 +24,20 @@ import ( "k8s.io/kubernetes/pkg/registry/service" "k8s.io/kubernetes/pkg/registry/service/portallocator" "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) // See ipallocator/controller/repair.go; this is a copy for ports. type Repair struct { interval time.Duration registry service.Registry - portRange util.PortRange + portRange net.PortRange alloc service.RangeRegistry } // NewRepair creates a controller that periodically ensures that all ports are uniquely allocated across the cluster // and generates informational warnings for a cluster that is not in sync. -func NewRepair(interval time.Duration, registry service.Registry, portRange util.PortRange, alloc service.RangeRegistry) *Repair { +func NewRepair(interval time.Duration, registry service.Registry, portRange net.PortRange, alloc service.RangeRegistry) *Repair { return &Repair{ interval: interval, registry: registry, diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index 9d070545f8..a90d264a94 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -34,7 +34,7 @@ import ( "k8s.io/kubernetes/pkg/registry/service/ipallocator" "k8s.io/kubernetes/pkg/registry/service/portallocator" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/watch" ) @@ -287,7 +287,7 @@ var _ = rest.Redirector(&REST{}) // ResourceLocation returns a URL to which one can send traffic for the specified service. func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "svcname", "svcname:port", or "scheme:svcname:port". - svcScheme, svcName, portStr, valid := util.SplitSchemeNamePort(id) + svcScheme, svcName, portStr, valid := utilnet.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id)) } diff --git a/pkg/registry/service/rest_test.go b/pkg/registry/service/rest_test.go index 0749fbe58f..57b0daeb74 100644 --- a/pkg/registry/service/rest_test.go +++ b/pkg/registry/service/rest_test.go @@ -27,7 +27,8 @@ import ( "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/service/ipallocator" "k8s.io/kubernetes/pkg/registry/service/portallocator" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" + "k8s.io/kubernetes/pkg/util/intstr" ) @@ -42,7 +43,7 @@ func NewTestREST(t *testing.T, endpoints *api.EndpointsList) (*REST, *registryte } r := ipallocator.NewCIDRRange(makeIPNet(t)) - portRange := util.PortRange{Base: 30000, Size: 1000} + portRange := utilnet.PortRange{Base: 30000, Size: 1000} portAllocator := portallocator.NewPortAllocator(portRange) storage := NewStorage(registry, endpointRegistry, r, portAllocator, nil) diff --git a/pkg/util/http.go b/pkg/util/net/http.go similarity index 92% rename from pkg/util/http.go rename to pkg/util/net/http.go index bdcc2bec4d..1c618accf8 100644 --- a/pkg/util/http.go +++ b/pkg/util/net/http.go @@ -1,5 +1,5 @@ /* -Copyright 2014 The Kubernetes Authors All rights reserved. +Copyright 2016 The Kubernetes Authors All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package net import ( "crypto/tls" @@ -111,3 +111,12 @@ func FormatURL(scheme string, host string, port int, path string) *url.URL { Path: path, } } + +func GetHTTPClient(req *http.Request) string { + if userAgent, ok := req.Header["User-Agent"]; ok { + if len(userAgent) > 0 { + return userAgent[0] + } + } + return "unknown" +} diff --git a/pkg/util/net/interface.go b/pkg/util/net/interface.go new file mode 100644 index 0000000000..cdf5ddb54a --- /dev/null +++ b/pkg/util/net/interface.go @@ -0,0 +1,278 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 net + +import ( + "bufio" + "encoding/hex" + "fmt" + "io" + "net" + "os" + + "strings" + + "github.com/golang/glog" +) + +type Route struct { + Interface string + Destination net.IP + Gateway net.IP + // TODO: add more fields here if needed +} + +func getRoutes(input io.Reader) ([]Route, error) { + routes := []Route{} + if input == nil { + return nil, fmt.Errorf("input is nil") + } + scanner := bufio.NewReader(input) + for { + line, err := scanner.ReadString('\n') + if err == io.EOF { + break + } + //ignore the headers in the route info + if strings.HasPrefix(line, "Iface") { + continue + } + fields := strings.Fields(line) + routes = append(routes, Route{}) + route := &routes[len(routes)-1] + route.Interface = fields[0] + ip, err := parseIP(fields[1]) + if err != nil { + return nil, err + } + route.Destination = ip + ip, err = parseIP(fields[2]) + if err != nil { + return nil, err + } + route.Gateway = ip + } + return routes, nil +} + +func parseIP(str string) (net.IP, error) { + if str == "" { + return nil, fmt.Errorf("input is nil") + } + bytes, err := hex.DecodeString(str) + if err != nil { + return nil, err + } + //TODO add ipv6 support + if len(bytes) != net.IPv4len { + return nil, fmt.Errorf("only IPv4 is supported") + } + bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0] + return net.IP(bytes), nil +} + +func isInterfaceUp(intf *net.Interface) bool { + if intf == nil { + return false + } + if intf.Flags&net.FlagUp != 0 { + glog.V(4).Infof("Interface %v is up", intf.Name) + return true + } + return false +} + +//getFinalIP method receives all the IP addrs of a Interface +//and returns a nil if the address is Loopback, Ipv6, link-local or nil. +//It returns a valid IPv4 if an Ipv4 address is found in the array. +func getFinalIP(addrs []net.Addr) (net.IP, error) { + if len(addrs) > 0 { + for i := range addrs { + glog.V(4).Infof("Checking addr %s.", addrs[i].String()) + ip, _, err := net.ParseCIDR(addrs[i].String()) + if err != nil { + return nil, err + } + //Only IPv4 + //TODO : add IPv6 support + if ip.To4() != nil { + if !ip.IsLoopback() && !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { + glog.V(4).Infof("IP found %v", ip) + return ip, nil + } else { + glog.V(4).Infof("Loopback/link-local found %v", ip) + } + } else { + glog.V(4).Infof("%v is not a valid IPv4 address", ip) + } + + } + } + return nil, nil +} + +func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) { + intf, err := nw.InterfaceByName(intfName) + if err != nil { + return nil, err + } + if isInterfaceUp(intf) { + addrs, err := nw.Addrs(intf) + if err != nil { + return nil, err + } + glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs) + finalIP, err := getFinalIP(addrs) + if err != nil { + return nil, err + } + if finalIP != nil { + glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP) + return finalIP, nil + } + } + + return nil, nil +} + +func flagsSet(flags net.Flags, test net.Flags) bool { + return flags&test != 0 +} + +func flagsClear(flags net.Flags, test net.Flags) bool { + return flags&test == 0 +} + +func chooseHostInterfaceNativeGo() (net.IP, error) { + intfs, err := net.Interfaces() + if err != nil { + return nil, err + } + i := 0 + var ip net.IP + for i = range intfs { + if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) { + addrs, err := intfs[i].Addrs() + if err != nil { + return nil, err + } + if len(addrs) > 0 { + for _, addr := range addrs { + if addrIP, _, err := net.ParseCIDR(addr.String()); err == nil { + if addrIP.To4() != nil { + ip = addrIP.To4() + if !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { + break + } + } + } + } + if ip != nil { + // This interface should suffice. + break + } + } + } + } + if ip == nil { + return nil, fmt.Errorf("no acceptable interface from host") + } + glog.V(4).Infof("Choosing interface %s (IP %v) as default", intfs[i].Name, ip) + return ip, nil +} + +//ChooseHostInterface is a method used fetch an IP for a daemon. +//It uses data from /proc/net/route file. +//For a node with no internet connection ,it returns error +//For a multi n/w interface node it returns the IP of the interface with gateway on it. +func ChooseHostInterface() (net.IP, error) { + inFile, err := os.Open("/proc/net/route") + if err != nil { + if os.IsNotExist(err) { + return chooseHostInterfaceNativeGo() + } + return nil, err + } + defer inFile.Close() + var nw networkInterfacer = networkInterface{} + return chooseHostInterfaceFromRoute(inFile, nw) +} + +type networkInterfacer interface { + InterfaceByName(intfName string) (*net.Interface, error) + Addrs(intf *net.Interface) ([]net.Addr, error) +} + +type networkInterface struct{} + +func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + intf, err := net.InterfaceByName(intfName) + if err != nil { + return nil, err + } + return intf, nil +} + +func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + addrs, err := intf.Addrs() + if err != nil { + return nil, err + } + return addrs, nil +} + +func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) { + routes, err := getRoutes(inFile) + if err != nil { + return nil, err + } + zero := net.IP{0, 0, 0, 0} + var finalIP net.IP + for i := range routes { + //find interface with gateway + if routes[i].Destination.Equal(zero) { + glog.V(4).Infof("Default route transits interface %q", routes[i].Interface) + finalIP, err := getIPFromInterface(routes[i].Interface, nw) + if err != nil { + return nil, err + } + if finalIP != nil { + glog.V(4).Infof("Choosing IP %v ", finalIP) + return finalIP, nil + } + } + } + glog.V(4).Infof("No valid IP found") + if finalIP == nil { + return nil, fmt.Errorf("Unable to select an IP.") + } + return nil, nil +} + +// If bind-address is usable, return it directly +// If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default +// interface. +func ChooseBindAddress(bindAddress net.IP) (net.IP, error) { + if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() { + hostIP, err := ChooseHostInterface() + if err != nil { + return nil, err + } + bindAddress = hostIP + } + return bindAddress, nil +} diff --git a/pkg/util/net/interface_test.go b/pkg/util/net/interface_test.go new file mode 100644 index 0000000000..9571e5b48b --- /dev/null +++ b/pkg/util/net/interface_test.go @@ -0,0 +1,300 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +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 net + +import ( + "fmt" + "io" + "net" + "strings" + "testing" +) + +const gatewayfirst = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const gatewaylast = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +` +const gatewaymiddle = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const noInternetConnection = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const nothing = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +` +const gatewayfirstIpv6_1 = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0AA1 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const gatewayfirstIpv6_2 = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0AA1 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const route_Invalidhex = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0AA 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` + +// Based on DigitalOcean COREOS +const gatewayfirstLinkLocal = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth0 00000000 0120372D 0001 0 0 0 00000000 0 0 0 +eth0 00000000 00000000 0001 0 0 2048 00000000 0 0 0 +` + +func TestGetRoutes(t *testing.T) { + testCases := []struct { + tcase string + route string + expected int + }{ + {"gatewayfirst", gatewayfirst, 4}, + {"gatewaymiddle", gatewaymiddle, 4}, + {"gatewaylast", gatewaylast, 4}, + {"nothing", nothing, 0}, + {"gatewayfirstIpv6_1", gatewayfirstIpv6_1, 0}, + {"gatewayfirstIpv6_2", gatewayfirstIpv6_2, 0}, + {"route_Invalidhex", route_Invalidhex, 0}, + } + for _, tc := range testCases { + r := strings.NewReader(tc.route) + routes, err := getRoutes(r) + if len(routes) != tc.expected { + t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, len(routes), err) + } + } +} + +func TestParseIP(t *testing.T) { + testCases := []struct { + tcase string + ip string + success bool + expected net.IP + }{ + {"empty", "", false, nil}, + {"too short", "AA", false, nil}, + {"too long", "0011223344", false, nil}, + {"invalid", "invalid!", false, nil}, + {"zero", "00000000", true, net.IP{0, 0, 0, 0}}, + {"ffff", "FFFFFFFF", true, net.IP{0xff, 0xff, 0xff, 0xff}}, + {"valid", "12345678", true, net.IP{120, 86, 52, 18}}, + } + for _, tc := range testCases { + ip, err := parseIP(tc.ip) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %q, got %q . err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestIsInterfaceUp(t *testing.T) { + testCases := []struct { + tcase string + intf net.Interface + expected bool + }{ + {"up", net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp}, true}, + {"down", net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0}, false}, + {"nothing", net.Interface{}, false}, + } + for _, tc := range testCases { + it := isInterfaceUp(&tc.intf) + if it != tc.expected { + t.Errorf("case[%v]: expected %v, got %v .", tc.tcase, tc.expected, it) + } + } +} + +type addrStruct struct{ val string } + +func (a addrStruct) Network() string { + return a.val +} +func (a addrStruct) String() string { + return a.val +} + +func TestFinalIP(t *testing.T) { + testCases := []struct { + tcase string + addr []net.Addr + expected net.IP + }{ + {"ipv6", []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}}, nil}, + {"invalidCIDR", []net.Addr{addrStruct{val: "fe80::2f7:67fff:fe6e:2956/64"}}, nil}, + {"loopback", []net.Addr{addrStruct{val: "127.0.0.1/24"}}, nil}, + {"ip4", []net.Addr{addrStruct{val: "10.254.12.132/17"}}, net.ParseIP("10.254.12.132")}, + + {"nothing", []net.Addr{}, nil}, + } + for _, tc := range testCases { + ip, err := getFinalIP(tc.addr) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestAddrs(t *testing.T) { + var nw networkInterfacer = validNetworkInterface{} + intf := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0} + addrs, err := nw.Addrs(&intf) + if err != nil { + t.Errorf("expected no error got : %v", err) + } + if len(addrs) != 2 { + t.Errorf("expected addrs: 2 got null") + } +} + +type validNetworkInterface struct { +} + +func (_ validNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} + return &c, nil +} +func (_ validNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}} + return ifat, nil +} + +type validNetworkInterfaceWithLinkLocal struct { +} + +func (_ validNetworkInterfaceWithLinkLocal) InterfaceByName(intfName string) (*net.Interface, error) { + c := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: net.FlagUp} + return &c, nil +} +func (_ validNetworkInterfaceWithLinkLocal) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "45.55.47.146/19"}} + return ifat, nil +} + +type validNetworkInterfacewithIpv6Only struct { +} + +func (_ validNetworkInterfacewithIpv6Only) InterfaceByName(intfName string) (*net.Interface, error) { + c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} + return &c, nil +} +func (_ validNetworkInterfacewithIpv6Only) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}} + return ifat, nil +} + +type noNetworkInterface struct { +} + +func (_ noNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return nil, fmt.Errorf("unable get Interface") +} +func (_ noNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + return nil, nil +} + +type networkInterfacewithNoAddrs struct { +} + +func (_ networkInterfacewithNoAddrs) InterfaceByName(intfName string) (*net.Interface, error) { + c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} + return &c, nil +} +func (_ networkInterfacewithNoAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) { + return nil, fmt.Errorf("unable get Addrs") +} + +type networkInterfacewithIpv6addrs struct { +} + +func (_ networkInterfacewithIpv6addrs) InterfaceByName(intfName string) (*net.Interface, error) { + c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} + return &c, nil +} +func (_ networkInterfacewithIpv6addrs) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "fe80::2f7:6ffff:fe6e:2956/64"}} + return ifat, nil +} + +func TestGetIPFromInterface(t *testing.T) { + testCases := []struct { + tcase string + nwname string + nw networkInterfacer + expected net.IP + }{ + {"valid", "eth3", validNetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"ipv6", "eth3", validNetworkInterfacewithIpv6Only{}, nil}, + {"nothing", "eth3", noNetworkInterface{}, nil}, + } + for _, tc := range testCases { + ip, err := getIPFromInterface(tc.nwname, tc.nw) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestChooseHostInterfaceFromRoute(t *testing.T) { + testCases := []struct { + tcase string + inFile io.Reader + nw networkInterfacer + expected net.IP + }{ + {"valid_routefirst", strings.NewReader(gatewayfirst), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"valid_routelast", strings.NewReader(gatewaylast), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"valid_routemiddle", strings.NewReader(gatewaymiddle), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"valid_routemiddle_ipv6", strings.NewReader(gatewaymiddle), validNetworkInterfacewithIpv6Only{}, nil}, + {"no internet connection", strings.NewReader(noInternetConnection), validNetworkInterface{}, nil}, + {"no non-link-local ip", strings.NewReader(gatewayfirstLinkLocal), validNetworkInterfaceWithLinkLocal{}, net.ParseIP("45.55.47.146")}, + {"no route", strings.NewReader(nothing), validNetworkInterface{}, nil}, + {"no route file", nil, validNetworkInterface{}, nil}, + {"no interfaces", nil, noNetworkInterface{}, nil}, + {"no interface Addrs", strings.NewReader(gatewaymiddle), networkInterfacewithNoAddrs{}, nil}, + {"Invalid Addrs", strings.NewReader(gatewaymiddle), networkInterfacewithIpv6addrs{}, nil}, + } + for _, tc := range testCases { + ip, err := chooseHostInterfaceFromRoute(tc.inFile, tc.nw) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} diff --git a/pkg/util/port_range.go b/pkg/util/net/port_range.go similarity index 99% rename from pkg/util/port_range.go rename to pkg/util/net/port_range.go index cfdde18af3..eb929c7f2c 100644 --- a/pkg/util/port_range.go +++ b/pkg/util/net/port_range.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package net import ( "fmt" diff --git a/pkg/util/port_range_test.go b/pkg/util/net/port_range_test.go similarity index 99% rename from pkg/util/port_range_test.go rename to pkg/util/net/port_range_test.go index f434519695..9eb081aa7d 100644 --- a/pkg/util/port_range_test.go +++ b/pkg/util/net/port_range_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package net import ( "testing" diff --git a/pkg/util/port_split.go b/pkg/util/net/port_split.go similarity index 99% rename from pkg/util/port_split.go rename to pkg/util/net/port_split.go index 176271189a..be40eb75f4 100644 --- a/pkg/util/port_split.go +++ b/pkg/util/net/port_split.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package net import ( "strings" diff --git a/pkg/util/port_split_test.go b/pkg/util/net/port_split_test.go similarity index 99% rename from pkg/util/port_split_test.go rename to pkg/util/net/port_split_test.go index 9d9e5fb0ff..2e9e135c07 100644 --- a/pkg/util/port_split_test.go +++ b/pkg/util/net/port_split_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package net import ( "testing" diff --git a/pkg/util/proxy/dial.go b/pkg/util/proxy/dial.go index 07982b7938..33cecb7ea1 100644 --- a/pkg/util/proxy/dial.go +++ b/pkg/util/proxy/dial.go @@ -25,14 +25,14 @@ import ( "github.com/golang/glog" - "k8s.io/kubernetes/pkg/util" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/third_party/golang/netutil" ) func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) { dialAddr := netutil.CanonicalAddr(url) - dialer, _ := util.Dialer(transport) + dialer, _ := utilnet.Dialer(transport) switch url.Scheme { case "http": @@ -45,7 +45,7 @@ func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) { var tlsConfig *tls.Config var tlsConn *tls.Conn var err error - tlsConfig, _ = util.TLSClientConfig(transport) + tlsConfig, _ = utilnet.TLSClientConfig(transport) if dialer != nil { // We have a dialer; use it to open the connection, then diff --git a/pkg/util/proxy/transport.go b/pkg/util/proxy/transport.go index c869fe5288..079670c0aa 100644 --- a/pkg/util/proxy/transport.go +++ b/pkg/util/proxy/transport.go @@ -31,7 +31,7 @@ import ( "golang.org/x/net/html" "golang.org/x/net/html/atom" - "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" ) @@ -123,7 +123,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { return t.rewriteResponse(req, resp) } -var _ = util.RoundTripperWrapper(&Transport{}) +var _ = net.RoundTripperWrapper(&Transport{}) func (rt *Transport) WrappedRoundTripper() http.RoundTripper { return rt.RoundTripper diff --git a/pkg/util/util.go b/pkg/util/util.go index 2a4ecfb2db..f39e3bbaa9 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -17,13 +17,8 @@ limitations under the License. package util import ( - "bufio" - "encoding/hex" "fmt" - "io" "math" - "net" - "net/http" "os" "reflect" "regexp" @@ -203,249 +198,6 @@ func AllPtrFieldsNil(obj interface{}) bool { return true } -type Route struct { - Interface string - Destination net.IP - Gateway net.IP - // TODO: add more fields here if needed -} - -func getRoutes(input io.Reader) ([]Route, error) { - routes := []Route{} - if input == nil { - return nil, fmt.Errorf("input is nil") - } - scanner := bufio.NewReader(input) - for { - line, err := scanner.ReadString('\n') - if err == io.EOF { - break - } - //ignore the headers in the route info - if strings.HasPrefix(line, "Iface") { - continue - } - fields := strings.Fields(line) - routes = append(routes, Route{}) - route := &routes[len(routes)-1] - route.Interface = fields[0] - ip, err := parseIP(fields[1]) - if err != nil { - return nil, err - } - route.Destination = ip - ip, err = parseIP(fields[2]) - if err != nil { - return nil, err - } - route.Gateway = ip - } - return routes, nil -} - -func parseIP(str string) (net.IP, error) { - if str == "" { - return nil, fmt.Errorf("input is nil") - } - bytes, err := hex.DecodeString(str) - if err != nil { - return nil, err - } - //TODO add ipv6 support - if len(bytes) != net.IPv4len { - return nil, fmt.Errorf("only IPv4 is supported") - } - bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0] - return net.IP(bytes), nil -} - -func isInterfaceUp(intf *net.Interface) bool { - if intf == nil { - return false - } - if intf.Flags&net.FlagUp != 0 { - glog.V(4).Infof("Interface %v is up", intf.Name) - return true - } - return false -} - -//getFinalIP method receives all the IP addrs of a Interface -//and returns a nil if the address is Loopback, Ipv6, link-local or nil. -//It returns a valid IPv4 if an Ipv4 address is found in the array. -func getFinalIP(addrs []net.Addr) (net.IP, error) { - if len(addrs) > 0 { - for i := range addrs { - glog.V(4).Infof("Checking addr %s.", addrs[i].String()) - ip, _, err := net.ParseCIDR(addrs[i].String()) - if err != nil { - return nil, err - } - //Only IPv4 - //TODO : add IPv6 support - if ip.To4() != nil { - if !ip.IsLoopback() && !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { - glog.V(4).Infof("IP found %v", ip) - return ip, nil - } else { - glog.V(4).Infof("Loopback/link-local found %v", ip) - } - } else { - glog.V(4).Infof("%v is not a valid IPv4 address", ip) - } - - } - } - return nil, nil -} - -func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) { - intf, err := nw.InterfaceByName(intfName) - if err != nil { - return nil, err - } - if isInterfaceUp(intf) { - addrs, err := nw.Addrs(intf) - if err != nil { - return nil, err - } - glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs) - finalIP, err := getFinalIP(addrs) - if err != nil { - return nil, err - } - if finalIP != nil { - glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP) - return finalIP, nil - } - } - - return nil, nil -} - -func flagsSet(flags net.Flags, test net.Flags) bool { - return flags&test != 0 -} - -func flagsClear(flags net.Flags, test net.Flags) bool { - return flags&test == 0 -} - -func chooseHostInterfaceNativeGo() (net.IP, error) { - intfs, err := net.Interfaces() - if err != nil { - return nil, err - } - i := 0 - var ip net.IP - for i = range intfs { - if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) { - addrs, err := intfs[i].Addrs() - if err != nil { - return nil, err - } - if len(addrs) > 0 { - for _, addr := range addrs { - if addrIP, _, err := net.ParseCIDR(addr.String()); err == nil { - if addrIP.To4() != nil { - ip = addrIP.To4() - if !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { - break - } - } - } - } - if ip != nil { - // This interface should suffice. - break - } - } - } - } - if ip == nil { - return nil, fmt.Errorf("no acceptable interface from host") - } - glog.V(4).Infof("Choosing interface %s (IP %v) as default", intfs[i].Name, ip) - return ip, nil -} - -//ChooseHostInterface is a method used fetch an IP for a daemon. -//It uses data from /proc/net/route file. -//For a node with no internet connection ,it returns error -//For a multi n/w interface node it returns the IP of the interface with gateway on it. -func ChooseHostInterface() (net.IP, error) { - inFile, err := os.Open("/proc/net/route") - if err != nil { - if os.IsNotExist(err) { - return chooseHostInterfaceNativeGo() - } - return nil, err - } - defer inFile.Close() - var nw networkInterfacer = networkInterface{} - return chooseHostInterfaceFromRoute(inFile, nw) -} - -type networkInterfacer interface { - InterfaceByName(intfName string) (*net.Interface, error) - Addrs(intf *net.Interface) ([]net.Addr, error) -} - -type networkInterface struct{} - -func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) { - intf, err := net.InterfaceByName(intfName) - if err != nil { - return nil, err - } - return intf, nil -} - -func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { - addrs, err := intf.Addrs() - if err != nil { - return nil, err - } - return addrs, nil -} - -func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) { - routes, err := getRoutes(inFile) - if err != nil { - return nil, err - } - zero := net.IP{0, 0, 0, 0} - var finalIP net.IP - for i := range routes { - //find interface with gateway - if routes[i].Destination.Equal(zero) { - glog.V(4).Infof("Default route transits interface %q", routes[i].Interface) - finalIP, err := getIPFromInterface(routes[i].Interface, nw) - if err != nil { - return nil, err - } - if finalIP != nil { - glog.V(4).Infof("Choosing IP %v ", finalIP) - return finalIP, nil - } - } - } - glog.V(4).Infof("No valid IP found") - if finalIP == nil { - return nil, fmt.Errorf("Unable to select an IP.") - } - return nil, nil -} - -func GetClient(req *http.Request) string { - if userAgent, ok := req.Header["User-Agent"]; ok { - if len(userAgent) > 0 { - return userAgent[0] - } - } - return "unknown" -} - func FileExists(filename string) (bool, error) { if _, err := os.Stat(filename); os.IsNotExist(err) { return false, nil @@ -486,17 +238,3 @@ func ReadDirNoExit(dirname string) ([]os.FileInfo, []error, error) { return list, errs, nil } - -// If bind-address is usable, return it directly -// If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default -// interface. -func ValidPublicAddrForMaster(bindAddress net.IP) (net.IP, error) { - if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() { - hostIP, err := ChooseHostInterface() - if err != nil { - return nil, err - } - bindAddress = hostIP - } - return bindAddress, nil -} diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index bb39b5b7a7..cd4605ca1e 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -18,9 +18,6 @@ package util import ( "fmt" - "io" - "net" - "strings" "testing" "time" ) @@ -182,278 +179,3 @@ func TestAllPtrFieldsNil(t *testing.T) { } } } - -const gatewayfirst = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 -eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` -const gatewaylast = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 -eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 -` -const gatewaymiddle = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` -const noInternetConnection = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` -const nothing = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -` -const gatewayfirstIpv6_1 = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 -eth3 0000FE0AA1 00000000 0001 0 0 0 0080FFFF 0 0 0 -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` -const gatewayfirstIpv6_2 = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth3 00000000 0100FE0AA1 0003 0 0 1024 00000000 0 0 0 -eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` -const route_Invalidhex = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth3 00000000 0100FE0AA 0003 0 0 1024 00000000 0 0 0 -eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 -docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 -virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -` - -// Based on DigitalOcean COREOS -const gatewayfirstLinkLocal = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -eth0 00000000 0120372D 0001 0 0 0 00000000 0 0 0 -eth0 00000000 00000000 0001 0 0 2048 00000000 0 0 0 -` - -func TestGetRoutes(t *testing.T) { - testCases := []struct { - tcase string - route string - expected int - }{ - {"gatewayfirst", gatewayfirst, 4}, - {"gatewaymiddle", gatewaymiddle, 4}, - {"gatewaylast", gatewaylast, 4}, - {"nothing", nothing, 0}, - {"gatewayfirstIpv6_1", gatewayfirstIpv6_1, 0}, - {"gatewayfirstIpv6_2", gatewayfirstIpv6_2, 0}, - {"route_Invalidhex", route_Invalidhex, 0}, - } - for _, tc := range testCases { - r := strings.NewReader(tc.route) - routes, err := getRoutes(r) - if len(routes) != tc.expected { - t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, len(routes), err) - } - } -} - -func TestParseIP(t *testing.T) { - testCases := []struct { - tcase string - ip string - success bool - expected net.IP - }{ - {"empty", "", false, nil}, - {"too short", "AA", false, nil}, - {"too long", "0011223344", false, nil}, - {"invalid", "invalid!", false, nil}, - {"zero", "00000000", true, net.IP{0, 0, 0, 0}}, - {"ffff", "FFFFFFFF", true, net.IP{0xff, 0xff, 0xff, 0xff}}, - {"valid", "12345678", true, net.IP{120, 86, 52, 18}}, - } - for _, tc := range testCases { - ip, err := parseIP(tc.ip) - if !ip.Equal(tc.expected) { - t.Errorf("case[%v]: expected %q, got %q . err : %v", tc.tcase, tc.expected, ip, err) - } - } -} - -func TestIsInterfaceUp(t *testing.T) { - testCases := []struct { - tcase string - intf net.Interface - expected bool - }{ - {"up", net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp}, true}, - {"down", net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0}, false}, - {"nothing", net.Interface{}, false}, - } - for _, tc := range testCases { - it := isInterfaceUp(&tc.intf) - if it != tc.expected { - t.Errorf("case[%v]: expected %v, got %v .", tc.tcase, tc.expected, it) - } - } -} - -type addrStruct struct{ val string } - -func (a addrStruct) Network() string { - return a.val -} -func (a addrStruct) String() string { - return a.val -} - -func TestFinalIP(t *testing.T) { - testCases := []struct { - tcase string - addr []net.Addr - expected net.IP - }{ - {"ipv6", []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}}, nil}, - {"invalidCIDR", []net.Addr{addrStruct{val: "fe80::2f7:67fff:fe6e:2956/64"}}, nil}, - {"loopback", []net.Addr{addrStruct{val: "127.0.0.1/24"}}, nil}, - {"ip4", []net.Addr{addrStruct{val: "10.254.12.132/17"}}, net.ParseIP("10.254.12.132")}, - - {"nothing", []net.Addr{}, nil}, - } - for _, tc := range testCases { - ip, err := getFinalIP(tc.addr) - if !ip.Equal(tc.expected) { - t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, ip, err) - } - } -} - -func TestAddrs(t *testing.T) { - var nw networkInterfacer = validNetworkInterface{} - intf := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0} - addrs, err := nw.Addrs(&intf) - if err != nil { - t.Errorf("expected no error got : %v", err) - } - if len(addrs) != 2 { - t.Errorf("expected addrs: 2 got null") - } -} - -type validNetworkInterface struct { -} - -func (_ validNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { - c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} - return &c, nil -} -func (_ validNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { - var ifat []net.Addr - ifat = []net.Addr{ - addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}} - return ifat, nil -} - -type validNetworkInterfaceWithLinkLocal struct { -} - -func (_ validNetworkInterfaceWithLinkLocal) InterfaceByName(intfName string) (*net.Interface, error) { - c := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: net.FlagUp} - return &c, nil -} -func (_ validNetworkInterfaceWithLinkLocal) Addrs(intf *net.Interface) ([]net.Addr, error) { - var ifat []net.Addr - ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "45.55.47.146/19"}} - return ifat, nil -} - -type validNetworkInterfacewithIpv6Only struct { -} - -func (_ validNetworkInterfacewithIpv6Only) InterfaceByName(intfName string) (*net.Interface, error) { - c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} - return &c, nil -} -func (_ validNetworkInterfacewithIpv6Only) Addrs(intf *net.Interface) ([]net.Addr, error) { - var ifat []net.Addr - ifat = []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}} - return ifat, nil -} - -type noNetworkInterface struct { -} - -func (_ noNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { - return nil, fmt.Errorf("unable get Interface") -} -func (_ noNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { - return nil, nil -} - -type networkInterfacewithNoAddrs struct { -} - -func (_ networkInterfacewithNoAddrs) InterfaceByName(intfName string) (*net.Interface, error) { - c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} - return &c, nil -} -func (_ networkInterfacewithNoAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) { - return nil, fmt.Errorf("unable get Addrs") -} - -type networkInterfacewithIpv6addrs struct { -} - -func (_ networkInterfacewithIpv6addrs) InterfaceByName(intfName string) (*net.Interface, error) { - c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp} - return &c, nil -} -func (_ networkInterfacewithIpv6addrs) Addrs(intf *net.Interface) ([]net.Addr, error) { - var ifat []net.Addr - ifat = []net.Addr{addrStruct{val: "fe80::2f7:6ffff:fe6e:2956/64"}} - return ifat, nil -} - -func TestGetIPFromInterface(t *testing.T) { - testCases := []struct { - tcase string - nwname string - nw networkInterfacer - expected net.IP - }{ - {"valid", "eth3", validNetworkInterface{}, net.ParseIP("10.254.71.145")}, - {"ipv6", "eth3", validNetworkInterfacewithIpv6Only{}, nil}, - {"nothing", "eth3", noNetworkInterface{}, nil}, - } - for _, tc := range testCases { - ip, err := getIPFromInterface(tc.nwname, tc.nw) - if !ip.Equal(tc.expected) { - t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) - } - } -} - -func TestChooseHostInterfaceFromRoute(t *testing.T) { - testCases := []struct { - tcase string - inFile io.Reader - nw networkInterfacer - expected net.IP - }{ - {"valid_routefirst", strings.NewReader(gatewayfirst), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, - {"valid_routelast", strings.NewReader(gatewaylast), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, - {"valid_routemiddle", strings.NewReader(gatewaymiddle), validNetworkInterface{}, net.ParseIP("10.254.71.145")}, - {"valid_routemiddle_ipv6", strings.NewReader(gatewaymiddle), validNetworkInterfacewithIpv6Only{}, nil}, - {"no internet connection", strings.NewReader(noInternetConnection), validNetworkInterface{}, nil}, - {"no non-link-local ip", strings.NewReader(gatewayfirstLinkLocal), validNetworkInterfaceWithLinkLocal{}, net.ParseIP("45.55.47.146")}, - {"no route", strings.NewReader(nothing), validNetworkInterface{}, nil}, - {"no route file", nil, validNetworkInterface{}, nil}, - {"no interfaces", nil, noNetworkInterface{}, nil}, - {"no interface Addrs", strings.NewReader(gatewaymiddle), networkInterfacewithNoAddrs{}, nil}, - {"Invalid Addrs", strings.NewReader(gatewaymiddle), networkInterfacewithIpv6addrs{}, nil}, - } - for _, tc := range testCases { - ip, err := chooseHostInterfaceFromRoute(tc.inFile, tc.nw) - if !ip.Equal(tc.expected) { - t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) - } - } -} diff --git a/pkg/watch/iowatcher.go b/pkg/watch/iowatcher.go index 6003d08860..5d9ac54e7c 100644 --- a/pkg/watch/iowatcher.go +++ b/pkg/watch/iowatcher.go @@ -23,6 +23,7 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) // Decoder allows StreamWatcher to watch any stream for which a Decoder can be written. @@ -102,7 +103,7 @@ func (sw *StreamWatcher) receive() { glog.V(1).Infof("Unexpected EOF during watch stream event decoding: %v", err) default: msg := "Unable to decode an event from the watch stream: %v" - if util.IsProbableEOF(err) { + if net.IsProbableEOF(err) { glog.V(5).Infof(msg, err) } else { glog.Errorf(msg, err) diff --git a/plugin/pkg/auth/authenticator/token/oidc/oidc.go b/plugin/pkg/auth/authenticator/token/oidc/oidc.go index 966661273f..5d61d01ccb 100644 --- a/plugin/pkg/auth/authenticator/token/oidc/oidc.go +++ b/plugin/pkg/auth/authenticator/token/oidc/oidc.go @@ -30,6 +30,7 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/net" ) var ( @@ -72,7 +73,7 @@ func New(issuerURL, clientID, caFile, usernameClaim string) (*OIDCAuthenticator, } // Copied from http.DefaultTransport. - tr := util.SetTransportDefaults(&http.Transport{ + tr := net.SetTransportDefaults(&http.Transport{ // According to golang's doc, if RootCAs is nil, // TLS uses the host's root CA set. TLSClientConfig: &tls.Config{RootCAs: roots}, diff --git a/test/e2e/proxy.go b/test/e2e/proxy.go index 7cc5d4308c..fb9b341269 100644 --- a/test/e2e/proxy.go +++ b/test/e2e/proxy.go @@ -27,8 +27,8 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" client "k8s.io/kubernetes/pkg/client/unversioned" - "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/intstr" + "k8s.io/kubernetes/pkg/util/net" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -133,13 +133,13 @@ func proxyContext(version string) { // Try proxying through the service and directly to through the pod. svcProxyURL := func(scheme, port string) string { - return prefix + "/proxy/namespaces/" + f.Namespace.Name + "/services/" + util.JoinSchemeNamePort(scheme, service.Name, port) + return prefix + "/proxy/namespaces/" + f.Namespace.Name + "/services/" + net.JoinSchemeNamePort(scheme, service.Name, port) } podProxyURL := func(scheme, port string) string { - return prefix + "/proxy/namespaces/" + f.Namespace.Name + "/pods/" + util.JoinSchemeNamePort(scheme, pods[0].Name, port) + return prefix + "/proxy/namespaces/" + f.Namespace.Name + "/pods/" + net.JoinSchemeNamePort(scheme, pods[0].Name, port) } subresourcePodProxyURL := func(scheme, port string) string { - return prefix + "/namespaces/" + f.Namespace.Name + "/pods/" + util.JoinSchemeNamePort(scheme, pods[0].Name, port) + "/proxy" + return prefix + "/namespaces/" + f.Namespace.Name + "/pods/" + net.JoinSchemeNamePort(scheme, pods[0].Name, port) + "/proxy" } expectations := map[string]string{ svcProxyURL("", "portname1") + "/": "foo", diff --git a/test/e2e/service.go b/test/e2e/service.go index cead642154..8283c53c63 100644 --- a/test/e2e/service.go +++ b/test/e2e/service.go @@ -35,12 +35,13 @@ import ( "k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/intstr" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/wait" ) // This should match whatever the default/configured range is -var ServiceNodePortRange = util.PortRange{Base: 30000, Size: 2768} +var ServiceNodePortRange = utilnet.PortRange{Base: 30000, Size: 2768} var _ = Describe("Services", func() { f := NewFramework("services")