mirror of https://github.com/k3s-io/k3s
Merge pull request #51686 from choury/fix_dup_unbind
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Fix duplicate unbind action in kube-proxy **What this PR does / why we need it**: Fix duplicate unbind action in kube-proxy. It will generate unnecessary error info If unbind multi-ports on one service . **Which issue this PR fixes**: fixes #51694 **Release-note**: ```release-note NONE ```pull/6/head
commit
02f0d92160
|
@ -13,6 +13,7 @@ go_test(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/proxy:go_default_library",
|
"//pkg/proxy:go_default_library",
|
||||||
|
"//pkg/proxy/ipvs/testing:go_default_library",
|
||||||
"//pkg/proxy/util:go_default_library",
|
"//pkg/proxy/util:go_default_library",
|
||||||
"//pkg/util/iptables:go_default_library",
|
"//pkg/util/iptables:go_default_library",
|
||||||
"//pkg/util/iptables/testing:go_default_library",
|
"//pkg/util/iptables/testing:go_default_library",
|
||||||
|
@ -30,7 +31,16 @@ go_test(
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["proxier.go"],
|
srcs = [
|
||||||
|
"netlink.go",
|
||||||
|
"netlink_unsupported.go",
|
||||||
|
"proxier.go",
|
||||||
|
] + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||||
|
"netlink_linux.go",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/api/helper:go_default_library",
|
"//pkg/api/helper:go_default_library",
|
||||||
|
@ -52,7 +62,12 @@ go_library(
|
||||||
"//vendor/k8s.io/apiserver/pkg/util/feature: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/client-go/tools/record:go_default_library",
|
||||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
],
|
] + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||||
|
"//vendor/github.com/vishvananda/netlink:go_default_library",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
@ -64,6 +79,9 @@ filegroup(
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [":package-srcs"],
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//pkg/proxy/ipvs/testing:all-srcs",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
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 ipvs
|
||||||
|
|
||||||
|
// 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(address, devName string) (exist bool, err error)
|
||||||
|
// UnbindAddress unbind address from the interface
|
||||||
|
UnbindAddress(address, devName string) error
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 ipvs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
type netlinkHandle struct {
|
||||||
|
netlink.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNetLinkHandle will crate a new netlinkHandle
|
||||||
|
func NewNetLinkHandle() NetLinkHandle {
|
||||||
|
return &netlinkHandle{netlink.Handle{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
|
||||||
|
func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
|
||||||
|
dev, err := h.LinkByName(devName)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error get interface: %s, err: %v", devName, err)
|
||||||
|
}
|
||||||
|
addr := net.ParseIP(address)
|
||||||
|
if addr == nil {
|
||||||
|
return false, fmt.Errorf("error parse ip address: %s", address)
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("error bind address: %s to interface: %s, err: %v", address, devName, err)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnbindAddress unbind address from the interface
|
||||||
|
func (h *netlinkHandle) UnbindAddress(address, devName string) error {
|
||||||
|
dev, err := h.LinkByName(devName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error get interface: %s, err: %v", devName, err)
|
||||||
|
}
|
||||||
|
addr := net.ParseIP(address)
|
||||||
|
if addr == nil {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 ipvs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyHandle struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNetLinkHandle will create an EmptyHandle
|
||||||
|
func NewNetLinkHandle() NetLinkHandle {
|
||||||
|
return &emptyHandle{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
|
||||||
|
func (h *emptyHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
|
||||||
|
return false, fmt.Errorf("netlink not supported for this platform")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnbindAddress unbind address from the interface
|
||||||
|
func (h *emptyHandle) UnbindAddress(address, devName string) error {
|
||||||
|
return fmt.Errorf("netlink not supported for this platform")
|
||||||
|
}
|
|
@ -134,6 +134,8 @@ type Proxier struct {
|
||||||
iptablesData *bytes.Buffer
|
iptablesData *bytes.Buffer
|
||||||
natChains *bytes.Buffer
|
natChains *bytes.Buffer
|
||||||
natRules *bytes.Buffer
|
natRules *bytes.Buffer
|
||||||
|
// Added as a member to the struct to allow injection for testing.
|
||||||
|
netlinkHandle NetLinkHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPGetter helps get node network interface IP
|
// IPGetter helps get node network interface IP
|
||||||
|
@ -270,6 +272,7 @@ func NewProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface,
|
||||||
iptablesData: bytes.NewBuffer(nil),
|
iptablesData: bytes.NewBuffer(nil),
|
||||||
natChains: bytes.NewBuffer(nil),
|
natChains: bytes.NewBuffer(nil),
|
||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
|
netlinkHandle: NewNetLinkHandle(),
|
||||||
}
|
}
|
||||||
burstSyncs := 2
|
burstSyncs := 2
|
||||||
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
||||||
|
@ -1292,7 +1295,7 @@ func (proxier *Proxier) syncService(svcName string, vs *utilipvs.VirtualServer,
|
||||||
// bind service address to dummy interface even if service not changed,
|
// bind service address to dummy interface even if service not changed,
|
||||||
// in case that service IP was removed by other processes
|
// in case that service IP was removed by other processes
|
||||||
if bindAddr {
|
if bindAddr {
|
||||||
_, err := proxier.ipvs.EnsureVirtualServerAddressBind(vs, DefaultDummyDevice)
|
_, err := proxier.netlinkHandle.EnsureAddressBind(vs.Address.String(), DefaultDummyDevice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to bind service address to dummy device %q: %v", svcName, err)
|
glog.Errorf("Failed to bind service address to dummy device %q: %v", svcName, err)
|
||||||
return err
|
return err
|
||||||
|
@ -1381,6 +1384,7 @@ func (proxier *Proxier) syncEndpoint(svcPortName proxy.ServicePortName, onlyNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (proxier *Proxier) cleanLegacyService(atciveServices map[string]bool, currentServices map[string]*utilipvs.VirtualServer) {
|
func (proxier *Proxier) cleanLegacyService(atciveServices map[string]bool, currentServices map[string]*utilipvs.VirtualServer) {
|
||||||
|
unbindIPAddr := sets.NewString()
|
||||||
for cS := range currentServices {
|
for cS := range currentServices {
|
||||||
if !atciveServices[cS] {
|
if !atciveServices[cS] {
|
||||||
svc := currentServices[cS]
|
svc := currentServices[cS]
|
||||||
|
@ -1388,10 +1392,14 @@ func (proxier *Proxier) cleanLegacyService(atciveServices map[string]bool, curre
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to delete service, error: %v", err)
|
glog.Errorf("Failed to delete service, error: %v", err)
|
||||||
}
|
}
|
||||||
err = proxier.ipvs.UnbindVirtualServerAddress(svc, DefaultDummyDevice)
|
unbindIPAddr.Insert(svc.Address.String())
|
||||||
if err != nil {
|
}
|
||||||
glog.Errorf("Failed to unbind service from dummy interface, error: %v", err)
|
}
|
||||||
}
|
|
||||||
|
for _, addr := range unbindIPAddr.UnsortedList() {
|
||||||
|
err := proxier.netlinkHandle.UnbindAddress(addr, DefaultDummyDevice)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to unbind service from dummy interface, error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
fakeexec "k8s.io/utils/exec/testing"
|
fakeexec "k8s.io/utils/exec/testing"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
||||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||||
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
||||||
|
@ -114,6 +115,7 @@ func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, nodeIPs
|
||||||
iptablesData: bytes.NewBuffer(nil),
|
iptablesData: bytes.NewBuffer(nil),
|
||||||
natChains: bytes.NewBuffer(nil),
|
natChains: bytes.NewBuffer(nil),
|
||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
|
netlinkHandle: netlinktest.NewFakeNetlinkHandle(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
licenses(["notice"])
|
||||||
|
|
||||||
|
load(
|
||||||
|
"@io_bazel_rules_go//go:def.bzl",
|
||||||
|
"go_library",
|
||||||
|
)
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = select({
|
||||||
|
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||||
|
"fake.go",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
)
|
|
@ -0,0 +1,38 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
//FakeNetlinkHandle mock implementation of proxy NetlinkHandle
|
||||||
|
type FakeNetlinkHandle struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewFakeNetlinkHandle will create a new FakeNetlinkHandle
|
||||||
|
func NewFakeNetlinkHandle() *FakeNetlinkHandle {
|
||||||
|
return &FakeNetlinkHandle{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//EnsureAddressBind is a mock implementation
|
||||||
|
func (h *FakeNetlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//UnbindAddress is a mock implementation
|
||||||
|
func (h *FakeNetlinkHandle) UnbindAddress(address, devName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -20,9 +20,6 @@ go_test(
|
||||||
deps = select({
|
deps = select({
|
||||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||||
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
"//vendor/github.com/docker/libnetwork/ipvs: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": [],
|
"//conditions:default": [],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -25,10 +25,6 @@ import (
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
// Flush clears all virtual servers in system. return occurred error immediately.
|
// Flush clears all virtual servers in system. return occurred error immediately.
|
||||||
Flush() error
|
Flush() error
|
||||||
// EnsureVirtualServerAddressBind checks if virtual server's address is bound to dummy interface and, if not, binds it. If the address is already bound, return true.
|
|
||||||
EnsureVirtualServerAddressBind(serv *VirtualServer, dev string) (exist bool, err error)
|
|
||||||
// UnbindVirtualServerAddress checks if virtual server's address is bound to dummy interface and, if so, unbinds it.
|
|
||||||
UnbindVirtualServerAddress(serv *VirtualServer, dev string) error
|
|
||||||
// AddVirtualServer creates the specified virtual server.
|
// AddVirtualServer creates the specified virtual server.
|
||||||
AddVirtualServer(*VirtualServer) error
|
AddVirtualServer(*VirtualServer) error
|
||||||
// UpdateVirtualServer updates an already existing virtual server. If the virtual server does not exist, return error.
|
// UpdateVirtualServer updates an already existing virtual server. If the virtual server does not exist, return error.
|
||||||
|
|
|
@ -30,8 +30,6 @@ import (
|
||||||
utilexec "k8s.io/utils/exec"
|
utilexec "k8s.io/utils/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cmdIP = "ip"
|
|
||||||
|
|
||||||
// runner implements Interface.
|
// runner implements Interface.
|
||||||
type runner struct {
|
type runner struct {
|
||||||
exec utilexec.Interface
|
exec utilexec.Interface
|
||||||
|
@ -51,34 +49,6 @@ func New(exec utilexec.Interface) Interface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnsureVirtualServerAddressBind is part of Interface.
|
|
||||||
func (runner *runner) EnsureVirtualServerAddressBind(vs *VirtualServer, dummyDev string) (exist bool, err error) {
|
|
||||||
addr := vs.Address.String()
|
|
||||||
args := []string{"addr", "add", addr, "dev", dummyDev}
|
|
||||||
out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
// "exit status 2" will be returned if the address is already bound to dummy device
|
|
||||||
if ee, ok := err.(utilexec.ExitError); ok {
|
|
||||||
if ee.Exited() && ee.ExitStatus() == 2 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("error bind address: %s to dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnbindVirtualServerAddress is part of Interface.
|
|
||||||
func (runner *runner) UnbindVirtualServerAddress(vs *VirtualServer, dummyDev string) error {
|
|
||||||
addr := vs.Address.String()
|
|
||||||
args := []string{"addr", "del", addr, "dev", dummyDev}
|
|
||||||
out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error unbind address: %s from dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddVirtualServer is part of Interface.
|
// AddVirtualServer is part of Interface.
|
||||||
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
|
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
|
||||||
eSvc, err := toBackendService(vs)
|
eSvc, err := toBackendService(vs)
|
||||||
|
|
|
@ -25,129 +25,9 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
"k8s.io/utils/exec"
|
|
||||||
fakeexec "k8s.io/utils/exec/testing"
|
|
||||||
|
|
||||||
"github.com/docker/libnetwork/ipvs"
|
"github.com/docker/libnetwork/ipvs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dummyDevice = "kube-ipvs0"
|
|
||||||
|
|
||||||
func TestEnsureVirtualServerAddressBind(t *testing.T) {
|
|
||||||
tests := []VirtualServer{
|
|
||||||
{
|
|
||||||
Address: net.ParseIP("10.20.30.40"),
|
|
||||||
Port: uint16(1234),
|
|
||||||
Protocol: string("TCP"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Address: net.ParseIP("2012::beef"),
|
|
||||||
Port: uint16(5678),
|
|
||||||
Protocol: string("UDP"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := range tests {
|
|
||||||
vs := &tests[i]
|
|
||||||
fcmd := fakeexec.FakeCmd{
|
|
||||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
|
||||||
// Success.
|
|
||||||
func() ([]byte, error) { return []byte{}, nil },
|
|
||||||
// Exists.
|
|
||||||
func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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...) },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
runner := New(&fexec)
|
|
||||||
// Success.
|
|
||||||
exists, err := runner.EnsureVirtualServerAddressBind(vs, dummyDevice)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("expected success, got %v", err)
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
t.Errorf("expected exists = false")
|
|
||||||
}
|
|
||||||
if fcmd.CombinedOutputCalls != 1 {
|
|
||||||
t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
|
||||||
}
|
|
||||||
IP := tests[i].Address.String()
|
|
||||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "add", IP, "dev", dummyDevice) {
|
|
||||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
|
||||||
}
|
|
||||||
// Exists.
|
|
||||||
exists, err = runner.EnsureVirtualServerAddressBind(vs, dummyDevice)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("expected success, got %v", err)
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
t.Errorf("expected exists = true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnbindVirtualServerAddress(t *testing.T) {
|
|
||||||
tests := []VirtualServer{
|
|
||||||
{
|
|
||||||
Address: net.ParseIP("2012::beef"),
|
|
||||||
Port: uint16(5678),
|
|
||||||
Protocol: string("UDP"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Address: net.ParseIP("10.20.30.40"),
|
|
||||||
Port: uint16(1234),
|
|
||||||
Protocol: string("TCP"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := range tests {
|
|
||||||
vs := &tests[i]
|
|
||||||
fcmd := fakeexec.FakeCmd{
|
|
||||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
|
||||||
// Success.
|
|
||||||
func() ([]byte, error) {
|
|
||||||
return []byte{}, nil
|
|
||||||
},
|
|
||||||
// Failure.
|
|
||||||
func() ([]byte, error) {
|
|
||||||
return nil, &fakeexec.FakeExitError{Status: 2}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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...)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
runner := New(&fexec)
|
|
||||||
// Success.
|
|
||||||
err := runner.UnbindVirtualServerAddress(vs, dummyDevice)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("expected success, got %v", err)
|
|
||||||
}
|
|
||||||
if fcmd.CombinedOutputCalls != 1 {
|
|
||||||
t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
|
||||||
}
|
|
||||||
IP := tests[i].Address.String()
|
|
||||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "del", IP, "dev", dummyDevice) {
|
|
||||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
|
||||||
}
|
|
||||||
// Failure.
|
|
||||||
err = runner.UnbindVirtualServerAddress(vs, dummyDevice)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_toVirtualServer(t *testing.T) {
|
func Test_toVirtualServer(t *testing.T) {
|
||||||
Tests := []struct {
|
Tests := []struct {
|
||||||
ipvsService ipvs.Service
|
ipvsService ipvs.Service
|
||||||
|
|
|
@ -36,14 +36,6 @@ func (runner *runner) Flush() error {
|
||||||
return fmt.Errorf("IPVS not supported for this platform")
|
return fmt.Errorf("IPVS not supported for this platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (runner *runner) EnsureVirtualServerAddressBind(*VirtualServer, string) (bool, error) {
|
|
||||||
return false, fmt.Errorf("IPVS not supported for this platform")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (runner *runner) UnbindVirtualServerAddress(*VirtualServer, string) error {
|
|
||||||
return fmt.Errorf("IPVS not supported for this platform")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (runner *runner) AddVirtualServer(*VirtualServer) error {
|
func (runner *runner) AddVirtualServer(*VirtualServer) error {
|
||||||
return fmt.Errorf("IPVS not supported for this platform")
|
return fmt.Errorf("IPVS not supported for this platform")
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,16 +55,6 @@ func toServiceKey(serv *utilipvs.VirtualServer) serviceKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//EnsureVirtualServerAddressBind is an empty implementation
|
|
||||||
func (*FakeIPVS) EnsureVirtualServerAddressBind(serv *utilipvs.VirtualServer, dev string) (exist bool, err error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//UnbindVirtualServerAddress is an empty implementation
|
|
||||||
func (*FakeIPVS) UnbindVirtualServerAddress(serv *utilipvs.VirtualServer, dev string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//AddVirtualServer is a fake implementation, it simply adds the VirtualServer into the cache store.
|
//AddVirtualServer is a fake implementation, it simply adds the VirtualServer into the cache store.
|
||||||
func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error {
|
func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error {
|
||||||
if serv == nil {
|
if serv == nil {
|
||||||
|
|
Loading…
Reference in New Issue