mirror of https://github.com/k3s-io/k3s
wrapper ipvs API as util
parent
dcefbaefec
commit
09a853257f
|
@ -27,6 +27,7 @@ filegroup(
|
|||
"//pkg/util/io:all-srcs",
|
||||
"//pkg/util/ipconfig:all-srcs",
|
||||
"//pkg/util/iptables:all-srcs",
|
||||
"//pkg/util/ipvs:all-srcs",
|
||||
"//pkg/util/keymutex:all-srcs",
|
||||
"//pkg/util/labels:all-srcs",
|
||||
"//pkg/util/limitwriter:all-srcs",
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"ipvs_test.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"ipvs_linux_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//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": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"ipvs.go",
|
||||
"ipvs_unsupported.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"ipvs_linux.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/ipvs/testing:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
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 (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe.
|
||||
type Interface interface {
|
||||
// Flush clears all virtual servers in system. return occurred error immediately.
|
||||
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(*VirtualServer) error
|
||||
// UpdateVirtualServer updates an already existing virtual server. If the virtual server does not exist, return error.
|
||||
UpdateVirtualServer(*VirtualServer) error
|
||||
// DeleteVirtualServer deletes the specified virtual server. If the virtual server does not exist, return error.
|
||||
DeleteVirtualServer(*VirtualServer) error
|
||||
// Given a partial virtual server, GetVirtualServer will return the specified virtual server information in the system.
|
||||
GetVirtualServer(*VirtualServer) (*VirtualServer, error)
|
||||
// GetVirtualServers lists all virtual servers in the system.
|
||||
GetVirtualServers() ([]*VirtualServer, error)
|
||||
// AddRealServer creates the specified real server for the specified virtual server.
|
||||
AddRealServer(*VirtualServer, *RealServer) error
|
||||
// GetRealServers returns all real servers for the specified virtual server.
|
||||
GetRealServers(*VirtualServer) ([]*RealServer, error)
|
||||
// DeleteRealServer deletes the specified real server from the specified virtual server.
|
||||
DeleteRealServer(*VirtualServer, *RealServer) error
|
||||
}
|
||||
|
||||
// VirtualServer is an user-oriented definition of an IPVS virtual server in its entirety.
|
||||
type VirtualServer struct {
|
||||
Address net.IP
|
||||
Protocol string
|
||||
Port uint16
|
||||
Scheduler string
|
||||
Flags ServiceFlags
|
||||
Timeout uint32
|
||||
}
|
||||
|
||||
// ServiceFlags is used to specify session affinity, ip hash etc.
|
||||
type ServiceFlags uint32
|
||||
|
||||
const (
|
||||
// FlagPersistent specify IPVS service session affinity
|
||||
FlagPersistent = 0x1
|
||||
)
|
||||
|
||||
// Equal check the equality of virtual server.
|
||||
// We don't use struct == since it doesn't work because of slice.
|
||||
func (svc *VirtualServer) Equal(other *VirtualServer) bool {
|
||||
return svc.Address.Equal(other.Address) &&
|
||||
svc.Protocol == other.Protocol &&
|
||||
svc.Port == other.Port &&
|
||||
svc.Scheduler == other.Scheduler &&
|
||||
svc.Flags == other.Flags &&
|
||||
svc.Timeout == other.Timeout
|
||||
}
|
||||
|
||||
func (svc *VirtualServer) String() string {
|
||||
return net.JoinHostPort(svc.Address.String(), strconv.Itoa(int(svc.Port))) + "/" + svc.Protocol
|
||||
}
|
||||
|
||||
// RealServer is an user-oriented definition of an IPVS real server in its entirety.
|
||||
type RealServer struct {
|
||||
Address net.IP
|
||||
Port uint16
|
||||
Weight int
|
||||
}
|
||||
|
||||
func (dest *RealServer) String() string {
|
||||
return net.JoinHostPort(dest.Address.String(), strconv.Itoa(int(dest.Port)))
|
||||
}
|
|
@ -0,0 +1,302 @@
|
|||
// +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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libnetwork/ipvs"
|
||||
"github.com/golang/glog"
|
||||
utilexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
const cmdIP = "ip"
|
||||
|
||||
// runner implements Interface.
|
||||
type runner struct {
|
||||
exec utilexec.Interface
|
||||
ipvsHandle *ipvs.Handle
|
||||
}
|
||||
|
||||
// New returns a new Interface which will call ipvs APIs.
|
||||
func New(exec utilexec.Interface) Interface {
|
||||
ihandle, err := ipvs.New("")
|
||||
if err != nil {
|
||||
glog.Errorf("IPVS interface can't be initialized, error: %v", err)
|
||||
return nil
|
||||
}
|
||||
return &runner{
|
||||
exec: exec,
|
||||
ipvsHandle: ihandle,
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureVirtualServerAddressBind is part of Interface.
|
||||
func (runner *runner) EnsureVirtualServerAddressBind(vs *VirtualServer, dummyDev string) (exist bool, err error) {
|
||||
addr := vs.Address.String() + "/32"
|
||||
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() + "/32"
|
||||
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.
|
||||
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
|
||||
eSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.ipvsHandle.NewService(eSvc)
|
||||
}
|
||||
|
||||
// UpdateVirtualServer is part of Interface.
|
||||
func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.ipvsHandle.UpdateService(bSvc)
|
||||
}
|
||||
|
||||
// DeleteVirtualServer is part of Interface.
|
||||
func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.ipvsHandle.DelService(bSvc)
|
||||
}
|
||||
|
||||
// GetVirtualServer is part of Interface.
|
||||
func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipvsService, err := runner.ipvsHandle.GetService(bSvc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
virtualServer, err := toVirtualServer(ipvsService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return virtualServer, nil
|
||||
}
|
||||
|
||||
// GetVirtualServers is part of Interface.
|
||||
func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
|
||||
ipvsServices, err := runner.ipvsHandle.GetServices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vss := make([]*VirtualServer, 0)
|
||||
for _, ipvsService := range ipvsServices {
|
||||
vs, err := toVirtualServer(ipvsService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vss = append(vss, vs)
|
||||
}
|
||||
return vss, nil
|
||||
}
|
||||
|
||||
// Flush is part of Interface. Currently we delete IPVS services one by one
|
||||
func (runner *runner) Flush() error {
|
||||
vss, err := runner.GetVirtualServers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, vs := range vss {
|
||||
err := runner.DeleteVirtualServer(vs)
|
||||
// TODO: aggregate errors?
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRealServer is part of Interface.
|
||||
func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bDst, err := toBackendDestination(rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.ipvsHandle.NewDestination(bSvc, bDst)
|
||||
}
|
||||
|
||||
// DeleteRealServer is part of Interface.
|
||||
func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bDst, err := toBackendDestination(rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.ipvsHandle.DelDestination(bSvc, bDst)
|
||||
}
|
||||
|
||||
// GetRealServers is part of Interface.
|
||||
func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
|
||||
bSvc, err := toBackendService(vs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bDestinations, err := runner.ipvsHandle.GetDestinations(bSvc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
realServers := make([]*RealServer, 0)
|
||||
for _, dest := range bDestinations {
|
||||
dst, err := toRealServer(dest)
|
||||
// TODO: aggregate errors?
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
realServers = append(realServers, dst)
|
||||
}
|
||||
return realServers, nil
|
||||
}
|
||||
|
||||
// toVirtualServer converts an IPVS service representation to the equivalent virtual server structure.
|
||||
func toVirtualServer(svc *ipvs.Service) (*VirtualServer, error) {
|
||||
if svc == nil {
|
||||
return nil, errors.New("ipvs svc should not be empty")
|
||||
}
|
||||
vs := &VirtualServer{
|
||||
Address: svc.Address,
|
||||
Port: svc.Port,
|
||||
Scheduler: svc.SchedName,
|
||||
Protocol: protocolNumbeToString(ProtoType(svc.Protocol)),
|
||||
Flags: ServiceFlags(svc.Flags),
|
||||
Timeout: svc.Timeout,
|
||||
}
|
||||
|
||||
if vs.Address == nil {
|
||||
if svc.AddressFamily == syscall.AF_INET {
|
||||
vs.Address = net.IPv4zero
|
||||
} else {
|
||||
vs.Address = net.IPv6zero
|
||||
}
|
||||
}
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
// toRealServer converts an IPVS destination representation to the equivalent real server structure.
|
||||
func toRealServer(dst *ipvs.Destination) (*RealServer, error) {
|
||||
if dst == nil {
|
||||
return nil, errors.New("ipvs destination should not be empty")
|
||||
}
|
||||
return &RealServer{
|
||||
Address: dst.Address,
|
||||
Port: dst.Port,
|
||||
Weight: dst.Weight,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// toBackendService converts an IPVS real server representation to the equivalent "backend" service structure.
|
||||
func toBackendService(vs *VirtualServer) (*ipvs.Service, error) {
|
||||
if vs == nil {
|
||||
return nil, errors.New("virtual server should not be empty")
|
||||
}
|
||||
bakSvc := &ipvs.Service{
|
||||
Address: vs.Address,
|
||||
Protocol: stringToProtocolNumber(vs.Protocol),
|
||||
Port: vs.Port,
|
||||
SchedName: vs.Scheduler,
|
||||
Flags: uint32(vs.Flags),
|
||||
Timeout: vs.Timeout,
|
||||
}
|
||||
|
||||
if ip4 := vs.Address.To4(); ip4 != nil {
|
||||
bakSvc.AddressFamily = syscall.AF_INET
|
||||
bakSvc.Netmask = 0xffffffff
|
||||
} else {
|
||||
bakSvc.AddressFamily = syscall.AF_INET6
|
||||
bakSvc.Netmask = 128
|
||||
}
|
||||
return bakSvc, nil
|
||||
}
|
||||
|
||||
// toBackendDestination converts an IPVS real server representation to the equivalent "backend" destination structure.
|
||||
func toBackendDestination(rs *RealServer) (*ipvs.Destination, error) {
|
||||
if rs == nil {
|
||||
return nil, errors.New("real server should not be empty")
|
||||
}
|
||||
return &ipvs.Destination{
|
||||
Address: rs.Address,
|
||||
Port: rs.Port,
|
||||
Weight: rs.Weight,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// stringToProtocolNumber returns the protocol value for the given name
|
||||
func stringToProtocolNumber(protocol string) uint16 {
|
||||
switch strings.ToLower(protocol) {
|
||||
case "tcp":
|
||||
return uint16(syscall.IPPROTO_TCP)
|
||||
case "udp":
|
||||
return uint16(syscall.IPPROTO_UDP)
|
||||
}
|
||||
return uint16(0)
|
||||
}
|
||||
|
||||
// protocolNumbeToString returns the name for the given protocol value.
|
||||
func protocolNumbeToString(proto ProtoType) string {
|
||||
switch proto {
|
||||
case syscall.IPPROTO_TCP:
|
||||
return "TCP"
|
||||
case syscall.IPPROTO_UDP:
|
||||
return "UDP"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ProtoType is IPVS service protocol type
|
||||
type ProtoType uint16
|
|
@ -0,0 +1,448 @@
|
|||
// +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 (
|
||||
"net"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/utils/exec"
|
||||
fakeexec "k8s.io/utils/exec/testing"
|
||||
|
||||
"github.com/docker/libnetwork/ipvs"
|
||||
)
|
||||
|
||||
const dummyDevice = "kube-ipvs0"
|
||||
|
||||
func TestEnsureVirtualServerAddressBind(t *testing.T) {
|
||||
vs := &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.40"),
|
||||
Port: uint16(1234),
|
||||
Protocol: string("TCP"),
|
||||
}
|
||||
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)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "add", "10.20.30.40/32", "dev", "kube-ipvs0") {
|
||||
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) {
|
||||
svc := &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.41"),
|
||||
Port: uint16(80),
|
||||
Protocol: string("TCP"),
|
||||
}
|
||||
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(svc, 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)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "del", "10.20.30.41/32", "dev", "kube-ipvs0") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
||||
}
|
||||
// Failure.
|
||||
err = runner.UnbindVirtualServerAddress(svc, dummyDevice)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toFrontendService(t *testing.T) {
|
||||
Tests := []struct {
|
||||
ipvsService ipvs.Service
|
||||
virtualServer VirtualServer
|
||||
}{
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: syscall.IPPROTO_TCP,
|
||||
Port: 80,
|
||||
FWMark: 0,
|
||||
SchedName: "",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 0xffffffff,
|
||||
AddressFamily: syscall.AF_INET,
|
||||
Address: nil,
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("0.0.0.0"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: syscall.IPPROTO_UDP,
|
||||
Port: 33434,
|
||||
FWMark: 0,
|
||||
SchedName: "wlc",
|
||||
Flags: 1234,
|
||||
Timeout: 100,
|
||||
Netmask: 128,
|
||||
AddressFamily: syscall.AF_INET6,
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "UDP",
|
||||
Port: 33434,
|
||||
Scheduler: "wlc",
|
||||
Flags: 1234,
|
||||
Timeout: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: 0,
|
||||
Port: 0,
|
||||
FWMark: 0,
|
||||
SchedName: "lc",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 0xffffffff,
|
||||
AddressFamily: syscall.AF_INET,
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "lc",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: 0,
|
||||
Port: 0,
|
||||
FWMark: 0,
|
||||
SchedName: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 128,
|
||||
AddressFamily: syscall.AF_INET6,
|
||||
Address: nil,
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("::0"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range Tests {
|
||||
got, err := toVirtualServer(&Tests[i].ipvsService)
|
||||
if err != nil {
|
||||
t.Errorf("case: %d, unexpected error: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*got, Tests[i].virtualServer) {
|
||||
t.Errorf("case: %d, got %#v, want %#v", i, *got, Tests[i].virtualServer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toBackendService(t *testing.T) {
|
||||
Tests := []struct {
|
||||
ipvsService ipvs.Service
|
||||
virtualServer VirtualServer
|
||||
}{
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: syscall.IPPROTO_TCP,
|
||||
Port: 80,
|
||||
FWMark: 0,
|
||||
SchedName: "",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 0xffffffff,
|
||||
AddressFamily: syscall.AF_INET,
|
||||
Address: net.ParseIP("0.0.0.0"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("0.0.0.0"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: syscall.IPPROTO_UDP,
|
||||
Port: 33434,
|
||||
FWMark: 0,
|
||||
SchedName: "wlc",
|
||||
Flags: 1234,
|
||||
Timeout: 100,
|
||||
Netmask: 128,
|
||||
AddressFamily: syscall.AF_INET6,
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "UDP",
|
||||
Port: 33434,
|
||||
Scheduler: "wlc",
|
||||
Flags: 1234,
|
||||
Timeout: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: 0,
|
||||
Port: 0,
|
||||
FWMark: 0,
|
||||
SchedName: "lc",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 0xffffffff,
|
||||
AddressFamily: syscall.AF_INET,
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "lc",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Service{
|
||||
Protocol: 0,
|
||||
Port: 0,
|
||||
FWMark: 0,
|
||||
SchedName: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
Netmask: 128,
|
||||
AddressFamily: syscall.AF_INET6,
|
||||
Address: net.ParseIP("::0"),
|
||||
PEName: "",
|
||||
},
|
||||
VirtualServer{
|
||||
Address: net.ParseIP("::0"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range Tests {
|
||||
got, err := toBackendService(&Tests[i].virtualServer)
|
||||
if err != nil {
|
||||
t.Errorf("case: %d, unexpected error: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*got, Tests[i].ipvsService) {
|
||||
t.Errorf("case: %d - got %#v, want %#v", i, *got, Tests[i].ipvsService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toFrontendDestination(t *testing.T) {
|
||||
Tests := []struct {
|
||||
ipvsDestination ipvs.Destination
|
||||
realServer RealServer
|
||||
}{
|
||||
{
|
||||
ipvs.Destination{
|
||||
Port: 54321,
|
||||
ConnectionFlags: 0,
|
||||
Weight: 1,
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
},
|
||||
RealServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Port: 54321,
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
ipvs.Destination{
|
||||
Port: 53,
|
||||
ConnectionFlags: 0,
|
||||
Weight: 1,
|
||||
Address: net.ParseIP("2002::cafe"),
|
||||
},
|
||||
RealServer{
|
||||
Address: net.ParseIP("2002::cafe"),
|
||||
Port: 53,
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
for i := range Tests {
|
||||
got, err := toRealServer(&Tests[i].ipvsDestination)
|
||||
if err != nil {
|
||||
t.Errorf("case %d unexpected error: %d", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*got, Tests[i].realServer) {
|
||||
t.Errorf("case %d Failed to translate Destination - got %#v, want %#v", i, *got, Tests[i].realServer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toBackendDestination(t *testing.T) {
|
||||
Tests := []struct {
|
||||
realServer RealServer
|
||||
ipvsDestination ipvs.Destination
|
||||
}{
|
||||
{
|
||||
RealServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Port: 54321,
|
||||
Weight: 1,
|
||||
},
|
||||
ipvs.Destination{
|
||||
Port: 54321,
|
||||
ConnectionFlags: 0,
|
||||
Weight: 1,
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
{
|
||||
RealServer{
|
||||
Address: net.ParseIP("2002::cafe"),
|
||||
Port: 53,
|
||||
Weight: 1,
|
||||
},
|
||||
ipvs.Destination{
|
||||
Port: 53,
|
||||
ConnectionFlags: 0,
|
||||
Weight: 1,
|
||||
Address: net.ParseIP("2002::cafe"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for i := range Tests {
|
||||
got, err := toBackendDestination(&Tests[i].realServer)
|
||||
if err != nil {
|
||||
t.Errorf("case %d unexpected error: %d", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(*got, Tests[i].ipvsDestination) {
|
||||
t.Errorf("case %d Failed to translate Destination - got %#v, want %#v", i, *got, Tests[i].ipvsDestination)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_stringToProtocolNumber(t *testing.T) {
|
||||
tests := []string{
|
||||
"TCP", "UDP", "ICMP",
|
||||
}
|
||||
expecteds := []uint16{
|
||||
uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0),
|
||||
}
|
||||
for i := range tests {
|
||||
got := stringToProtocolNumber(tests[i])
|
||||
if got != expecteds[i] {
|
||||
t.Errorf("stringToProtocolNumber() failed - got %#v, want %#v",
|
||||
got, expecteds[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_protocolNumberToString(t *testing.T) {
|
||||
tests := []ProtoType{
|
||||
syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, ProtoType(0),
|
||||
}
|
||||
expecteds := []string{
|
||||
"TCP", "UDP", "",
|
||||
}
|
||||
for i := range tests {
|
||||
got := protocolNumbeToString(tests[i])
|
||||
if got != expecteds[i] {
|
||||
t.Errorf("protocolNumbeToString() failed - got %#v, want %#v",
|
||||
got, expecteds[i])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
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 (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVirtualServerEqual(t *testing.T) {
|
||||
Tests := []struct {
|
||||
svcA *VirtualServer
|
||||
svcB *VirtualServer
|
||||
equal bool
|
||||
reason string
|
||||
}{
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.40"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.41"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "IPv4 address not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("2017::beef"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "IPv6 address not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "TCP",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beeef"),
|
||||
Protocol: "UDP",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "Protocol not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "TCP",
|
||||
Port: 8080,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "Port not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "rr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "wlc",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "Scheduler not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "rr",
|
||||
Flags: 2,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "rr",
|
||||
Flags: 3,
|
||||
Timeout: 0,
|
||||
},
|
||||
equal: false,
|
||||
reason: "Flags not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 0,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "",
|
||||
Port: 0,
|
||||
Scheduler: "wrr",
|
||||
Flags: 0,
|
||||
Timeout: 10800,
|
||||
},
|
||||
equal: false,
|
||||
reason: "Timeout not equal",
|
||||
},
|
||||
{
|
||||
svcA: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "rr",
|
||||
Flags: 0x1,
|
||||
Timeout: 10800,
|
||||
},
|
||||
svcB: &VirtualServer{
|
||||
Address: net.ParseIP("1.2.3.4"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
Scheduler: "rr",
|
||||
Flags: 0x1,
|
||||
Timeout: 10800,
|
||||
},
|
||||
equal: true,
|
||||
reason: "All fields equal",
|
||||
},
|
||||
}
|
||||
|
||||
for i := range Tests {
|
||||
equal := Tests[i].svcA.Equal(Tests[i].svcB)
|
||||
if equal != Tests[i].equal {
|
||||
t.Errorf("case: %d got %v, expected %v, reason: %s", i, equal, Tests[i].equal, Tests[i].reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFrontendServiceString(t *testing.T) {
|
||||
Tests := []struct {
|
||||
svc *VirtualServer
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
svc: &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.40"),
|
||||
Protocol: "TCP",
|
||||
Port: 80,
|
||||
},
|
||||
expected: "10.20.30.40:80/TCP",
|
||||
},
|
||||
{
|
||||
svc: &VirtualServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Protocol: "UDP",
|
||||
Port: 8080,
|
||||
},
|
||||
expected: "[2012::beef]:8080/UDP",
|
||||
},
|
||||
{
|
||||
svc: &VirtualServer{
|
||||
Address: net.ParseIP("10.20.30.41"),
|
||||
Protocol: "ESP",
|
||||
Port: 1234,
|
||||
},
|
||||
expected: "10.20.30.41:1234/ESP",
|
||||
},
|
||||
}
|
||||
|
||||
for i := range Tests {
|
||||
if Tests[i].expected != Tests[i].svc.String() {
|
||||
t.Errorf("case: %d got %v, expected %v", i, Tests[i].svc.String(), Tests[i].expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFrontendDestinationString(t *testing.T) {
|
||||
Tests := []struct {
|
||||
svc *RealServer
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
svc: &RealServer{
|
||||
Address: net.ParseIP("10.20.30.40"),
|
||||
Port: 80,
|
||||
},
|
||||
expected: "10.20.30.40:80",
|
||||
},
|
||||
{
|
||||
svc: &RealServer{
|
||||
Address: net.ParseIP("2012::beef"),
|
||||
Port: 8080,
|
||||
},
|
||||
expected: "[2012::beef]:8080",
|
||||
},
|
||||
}
|
||||
|
||||
for i := range Tests {
|
||||
if Tests[i].expected != Tests[i].svc.String() {
|
||||
t.Errorf("case: %d got %v, expected %v", i, Tests[i].svc.String(), Tests[i].expected)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// +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"
|
||||
|
||||
utilexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// New returns a dummy Interface for unsupported platform.
|
||||
func New(utilexec.Interface) Interface {
|
||||
return &runner{}
|
||||
}
|
||||
|
||||
type runner struct {
|
||||
}
|
||||
|
||||
func (runner *runner) Flush() error {
|
||||
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 {
|
||||
return fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) UpdateVirtualServer(*VirtualServer) error {
|
||||
return fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) DeleteVirtualServer(*VirtualServer) error {
|
||||
return fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) GetVirtualServer(*VirtualServer) (*VirtualServer, error) {
|
||||
return nil, fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
|
||||
return nil, fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) AddRealServer(*VirtualServer, *RealServer) error {
|
||||
return fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) GetRealServers(*VirtualServer) ([]*RealServer, error) {
|
||||
return nil, fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
func (runner *runner) DeleteRealServer(*VirtualServer, *RealServer) error {
|
||||
return fmt.Errorf("IPVS not supported for this platform")
|
||||
}
|
||||
|
||||
var _ = Interface(&runner{})
|
|
@ -0,0 +1,28 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/util/ipvs:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
)
|
||||
|
||||
//FakeIPVS no-op implementation of ipvs Interface
|
||||
type FakeIPVS struct {
|
||||
Scheduler string
|
||||
Services map[serviceKey]*utilipvs.VirtualServer
|
||||
Destinations map[serviceKey][]*utilipvs.RealServer
|
||||
}
|
||||
|
||||
type serviceKey struct {
|
||||
IP string
|
||||
Port uint16
|
||||
Protocol string
|
||||
}
|
||||
|
||||
func (s *serviceKey) String() string {
|
||||
return fmt.Sprintf("%s:%d/%s", s.IP, s.Port, s.Protocol)
|
||||
}
|
||||
|
||||
//NewFake creates a fake ipvs strucuter
|
||||
func NewFake() *FakeIPVS {
|
||||
return &FakeIPVS{
|
||||
Services: make(map[serviceKey]*utilipvs.VirtualServer),
|
||||
Destinations: make(map[serviceKey][]*utilipvs.RealServer),
|
||||
}
|
||||
}
|
||||
|
||||
func toServiceKey(serv *utilipvs.VirtualServer) serviceKey {
|
||||
return serviceKey{
|
||||
IP: serv.Address.To4().String(),
|
||||
Port: serv.Port,
|
||||
Protocol: serv.Protocol,
|
||||
}
|
||||
}
|
||||
|
||||
//EnsureVirtualServerAddressBind is a fake implementation
|
||||
func (*FakeIPVS) EnsureVirtualServerAddressBind(serv *utilipvs.VirtualServer, dev string) (exist bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
//UnbindVirtualServerAddress is a fake implementation
|
||||
func (*FakeIPVS) UnbindVirtualServerAddress(serv *utilipvs.VirtualServer, dev string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//AddVirtualServer is a fake implementation
|
||||
func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error {
|
||||
if serv == nil {
|
||||
return fmt.Errorf("Failed to add service: service can't be nil")
|
||||
}
|
||||
key := toServiceKey(serv)
|
||||
f.Services[key] = serv
|
||||
// make sure no destination present when creating new service
|
||||
f.Destinations = make(map[serviceKey][]*utilipvs.RealServer)
|
||||
return nil
|
||||
}
|
||||
|
||||
//UpdateVirtualServer is a fake implementation
|
||||
func (f *FakeIPVS) UpdateVirtualServer(serv *utilipvs.VirtualServer) error {
|
||||
if serv == nil {
|
||||
return fmt.Errorf("Failed to update service, service can't be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//DeleteVirtualServer is a fake implementation
|
||||
func (f *FakeIPVS) DeleteVirtualServer(serv *utilipvs.VirtualServer) error {
|
||||
if serv == nil {
|
||||
return fmt.Errorf("Failed to delete service: service can't be nil")
|
||||
}
|
||||
key := toServiceKey(serv)
|
||||
delete(f.Services, key)
|
||||
// clear specific destinations as well
|
||||
f.Destinations[key] = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
//GetVirtualServer is a fake implementation
|
||||
func (f *FakeIPVS) GetVirtualServer(serv *utilipvs.VirtualServer) (*utilipvs.VirtualServer, error) {
|
||||
if serv == nil {
|
||||
return nil, fmt.Errorf("Failed to get service: service can't be nil")
|
||||
}
|
||||
key := toServiceKey(serv)
|
||||
svc, found := f.Services[key]
|
||||
if found {
|
||||
return svc, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Not found serv: %v", key.String())
|
||||
}
|
||||
|
||||
//GetVirtualServers is a fake implementation
|
||||
func (f *FakeIPVS) GetVirtualServers() ([]*utilipvs.VirtualServer, error) {
|
||||
res := make([]*utilipvs.VirtualServer, 0)
|
||||
for _, svc := range f.Services {
|
||||
res = append(res, svc)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
//Flush is a fake implementation
|
||||
func (f *FakeIPVS) Flush() error {
|
||||
// directly drop old data
|
||||
f.Services = nil
|
||||
f.Destinations = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
//AddRealServer is a fake implementation
|
||||
func (f *FakeIPVS) AddRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error {
|
||||
if serv == nil || dest == nil {
|
||||
return fmt.Errorf("Failed to add destination for service, neither service nor destination shouldn't be nil")
|
||||
}
|
||||
key := toServiceKey(serv)
|
||||
if _, ok := f.Services[key]; !ok {
|
||||
return fmt.Errorf("Failed to add destination for service %v, service not found", key.String())
|
||||
}
|
||||
dests := f.Destinations[key]
|
||||
if dests == nil {
|
||||
dests = make([]*utilipvs.RealServer, 0)
|
||||
f.Destinations[key] = dests
|
||||
}
|
||||
f.Destinations[key] = append(f.Destinations[key], dest)
|
||||
return nil
|
||||
}
|
||||
|
||||
//GetRealServers is a fake implementation
|
||||
func (f *FakeIPVS) GetRealServers(serv *utilipvs.VirtualServer) ([]*utilipvs.RealServer, error) {
|
||||
if serv == nil {
|
||||
return nil, fmt.Errorf("Failed to get destination for nil service")
|
||||
}
|
||||
key := toServiceKey(serv)
|
||||
if _, ok := f.Services[key]; !ok {
|
||||
return nil, fmt.Errorf("Failed to get destinations for service %v, service not found", key.String())
|
||||
}
|
||||
return f.Destinations[key], nil
|
||||
}
|
||||
|
||||
//DeleteRealServer is a fake implementation
|
||||
func (*FakeIPVS) DeleteRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error {
|
||||
if serv == nil || dest == nil {
|
||||
return fmt.Errorf("Failed to delete destination, neither service nor destination can't be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ = utilipvs.Interface(&FakeIPVS{})
|
|
@ -140,6 +140,7 @@ filegroup(
|
|||
"//vendor/github.com/docker/go-connections/sockets:all-srcs",
|
||||
"//vendor/github.com/docker/go-connections/tlsconfig:all-srcs",
|
||||
"//vendor/github.com/docker/go-units:all-srcs",
|
||||
"//vendor/github.com/docker/libnetwork/ipvs:all-srcs",
|
||||
"//vendor/github.com/docker/spdystream:all-srcs",
|
||||
"//vendor/github.com/elazarl/go-bindata-assetfs:all-srcs",
|
||||
"//vendor/github.com/elazarl/goproxy:all-srcs",
|
||||
|
@ -306,6 +307,7 @@ filegroup(
|
|||
"//vendor/github.com/syndtr/gocapability/capability:all-srcs",
|
||||
"//vendor/github.com/ugorji/go/codec:all-srcs",
|
||||
"//vendor/github.com/vishvananda/netlink:all-srcs",
|
||||
"//vendor/github.com/vishvananda/netns:all-srcs",
|
||||
"//vendor/github.com/vmware/govmomi:all-srcs",
|
||||
"//vendor/github.com/vmware/photon-controller-go-sdk/SSPI:all-srcs",
|
||||
"//vendor/github.com/vmware/photon-controller-go-sdk/photon:all-srcs",
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"addr.go",
|
||||
"class.go",
|
||||
"conntrack_unspecified.go",
|
||||
"filter.go",
|
||||
"genetlink_unspecified.go",
|
||||
"handle_unspecified.go",
|
||||
"link.go",
|
||||
"neigh.go",
|
||||
"netlink.go",
|
||||
"netlink_unspecified.go",
|
||||
"order.go",
|
||||
"protinfo.go",
|
||||
"qdisc.go",
|
||||
"route.go",
|
||||
"route_unspecified.go",
|
||||
"rule.go",
|
||||
"socket.go",
|
||||
"xfrm.go",
|
||||
"xfrm_policy.go",
|
||||
"xfrm_state.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"addr_linux.go",
|
||||
"bpf_linux.go",
|
||||
"bridge_linux.go",
|
||||
"class_linux.go",
|
||||
"conntrack_linux.go",
|
||||
"filter_linux.go",
|
||||
"genetlink_linux.go",
|
||||
"gtp_linux.go",
|
||||
"handle_linux.go",
|
||||
"link_linux.go",
|
||||
"link_tuntap_linux.go",
|
||||
"neigh_linux.go",
|
||||
"netlink_linux.go",
|
||||
"protinfo_linux.go",
|
||||
"qdisc_linux.go",
|
||||
"route_linux.go",
|
||||
"rule_linux.go",
|
||||
"socket_linux.go",
|
||||
"xfrm_monitor_linux.go",
|
||||
"xfrm_policy_linux.go",
|
||||
"xfrm_state_linux.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
cgo = True,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/vishvananda/netlink/nl:go_default_library",
|
||||
"//vendor/github.com/vishvananda/netns:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/vishvananda/netlink/nl:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,47 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"nl_unspecified.go",
|
||||
"syscall.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"addr_linux.go",
|
||||
"bridge_linux.go",
|
||||
"conntrack_linux.go",
|
||||
"genetlink_linux.go",
|
||||
"link_linux.go",
|
||||
"mpls_linux.go",
|
||||
"nl_linux.go",
|
||||
"route_linux.go",
|
||||
"tc_linux.go",
|
||||
"xfrm_linux.go",
|
||||
"xfrm_monitor_linux.go",
|
||||
"xfrm_policy_linux.go",
|
||||
"xfrm_state_linux.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//vendor/github.com/vishvananda/netns:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -11,8 +11,13 @@ go_library(
|
|||
name = "go_default_library",
|
||||
srcs = [
|
||||
"netns.go",
|
||||
"netns_linux.go",
|
||||
],
|
||||
"netns_unspecified.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"netns_linux.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue