From f21cf887976684bd53a03c95877b2152d0e0ae94 Mon Sep 17 00:00:00 2001 From: m1093782566 Date: Wed, 27 Sep 2017 18:17:09 +0800 Subject: [PATCH] implement delete real server for fakeIPVS and add UTs --- pkg/util/ipvs/ipvs.go | 12 ++- pkg/util/ipvs/ipvs_test.go | 101 +++++++++++++++++++ pkg/util/ipvs/testing/BUILD | 8 ++ pkg/util/ipvs/testing/fake.go | 45 ++++++--- pkg/util/ipvs/testing/fake_test.go | 149 +++++++++++++++++++++++++++++ 5 files changed, 299 insertions(+), 16 deletions(-) create mode 100644 pkg/util/ipvs/testing/fake_test.go diff --git a/pkg/util/ipvs/ipvs.go b/pkg/util/ipvs/ipvs.go index 5b51acbf8f..c474e921e4 100644 --- a/pkg/util/ipvs/ipvs.go +++ b/pkg/util/ipvs/ipvs.go @@ -89,6 +89,14 @@ type RealServer struct { Weight int } -func (dest *RealServer) String() string { - return net.JoinHostPort(dest.Address.String(), strconv.Itoa(int(dest.Port))) +func (rs *RealServer) String() string { + return net.JoinHostPort(rs.Address.String(), strconv.Itoa(int(rs.Port))) +} + +// Equal check the equality of real server. +// We don't use struct == since it doesn't work because of slice. +func (rs *RealServer) Equal(other *RealServer) bool { + return rs.Address.Equal(other.Address) && + rs.Port == other.Port && + rs.Weight == other.Weight } diff --git a/pkg/util/ipvs/ipvs_test.go b/pkg/util/ipvs/ipvs_test.go index b4abe93831..ae92f02bf8 100644 --- a/pkg/util/ipvs/ipvs_test.go +++ b/pkg/util/ipvs/ipvs_test.go @@ -198,6 +198,107 @@ func TestVirtualServerEqual(t *testing.T) { } } +func TestRealServerEqual(t *testing.T) { + Tests := []struct { + rsA *RealServer + rsB *RealServer + equal bool + reason string + }{ + { + rsA: &RealServer{ + Address: net.ParseIP("10.20.30.40"), + Port: 80, + Weight: 1, + }, + rsB: &RealServer{ + Address: net.ParseIP("10.20.30.41"), + Port: 80, + Weight: 1, + }, + equal: false, + reason: "IPv4 address not equal", + }, + { + rsA: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 80, + Weight: 1, + }, + rsB: &RealServer{ + Address: net.ParseIP("2017::beef"), + Port: 80, + Weight: 1, + }, + equal: false, + reason: "IPv6 address not equal", + }, + { + rsA: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 80, + Weight: 1, + }, + rsB: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 8080, + Weight: 1, + }, + equal: false, + reason: "Port not equal", + }, + { + rsA: &RealServer{ + Address: net.ParseIP("10.20.30.40"), + Port: 8080, + Weight: 1, + }, + rsB: &RealServer{ + Address: net.ParseIP("10.20.30.40"), + Port: 8080, + Weight: 10, + }, + equal: false, + reason: "Weight not equal", + }, + { + rsA: &RealServer{ + Address: net.ParseIP("1.2.3.4"), + Port: 3080, + Weight: 10, + }, + rsB: &RealServer{ + Address: net.ParseIP("1.2.3.4"), + Port: 3080, + Weight: 10, + }, + equal: true, + reason: "All fields equal", + }, + { + rsA: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 3080, + Weight: 10, + }, + rsB: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 3080, + Weight: 10, + }, + equal: true, + reason: "All fields equal", + }, + } + + for i := range Tests { + equal := Tests[i].rsA.Equal(Tests[i].rsB) + 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 diff --git a/pkg/util/ipvs/testing/BUILD b/pkg/util/ipvs/testing/BUILD index 6789e58f13..1ec5c067de 100644 --- a/pkg/util/ipvs/testing/BUILD +++ b/pkg/util/ipvs/testing/BUILD @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( @@ -23,3 +24,10 @@ filegroup( srcs = [":package-srcs"], tags = ["automanaged"], ) + +go_test( + name = "go_default_test", + srcs = ["fake_test.go"], + library = ":go_default_library", + deps = ["//pkg/util/ipvs:go_default_library"], +) diff --git a/pkg/util/ipvs/testing/fake.go b/pkg/util/ipvs/testing/fake.go index de4acf546e..8e155024c6 100644 --- a/pkg/util/ipvs/testing/fake.go +++ b/pkg/util/ipvs/testing/fake.go @@ -39,7 +39,7 @@ func (s *serviceKey) String() string { return fmt.Sprintf("%s:%d/%s", s.IP, s.Port, s.Protocol) } -//NewFake creates a fake ipvs strucuter +//NewFake creates a fake ipvs implementation - a cache store. func NewFake() *FakeIPVS { return &FakeIPVS{ Services: make(map[serviceKey]*utilipvs.VirtualServer), @@ -55,20 +55,20 @@ func toServiceKey(serv *utilipvs.VirtualServer) serviceKey { } } -//EnsureVirtualServerAddressBind is a fake implementation +//EnsureVirtualServerAddressBind is an empty implementation func (*FakeIPVS) EnsureVirtualServerAddressBind(serv *utilipvs.VirtualServer, dev string) (exist bool, err error) { return true, nil } -//UnbindVirtualServerAddress is a fake implementation +//UnbindVirtualServerAddress is an empty implementation func (*FakeIPVS) UnbindVirtualServerAddress(serv *utilipvs.VirtualServer, dev string) error { return nil } -//AddVirtualServer is a fake implementation +//AddVirtualServer is a fake implementation, it simply adds the VirtualServer into the cache store. func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error { if serv == nil { - return fmt.Errorf("Failed to add service: service can't be nil") + return fmt.Errorf("Failed to add virtual server, error: virtual server can't be nil") } key := toServiceKey(serv) f.Services[key] = serv @@ -77,7 +77,7 @@ func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error { return nil } -//UpdateVirtualServer is a fake implementation +//UpdateVirtualServer is an empty implementation func (f *FakeIPVS) UpdateVirtualServer(serv *utilipvs.VirtualServer) error { if serv == nil { return fmt.Errorf("Failed to update service, service can't be nil") @@ -85,7 +85,7 @@ func (f *FakeIPVS) UpdateVirtualServer(serv *utilipvs.VirtualServer) error { return nil } -//DeleteVirtualServer is a fake implementation +//DeleteVirtualServer is a fake implementation, it simply deletes the VirtualServer from the cache store. func (f *FakeIPVS) DeleteVirtualServer(serv *utilipvs.VirtualServer) error { if serv == nil { return fmt.Errorf("Failed to delete service: service can't be nil") @@ -97,7 +97,7 @@ func (f *FakeIPVS) DeleteVirtualServer(serv *utilipvs.VirtualServer) error { return nil } -//GetVirtualServer is a fake implementation +//GetVirtualServer is a fake implementation, it tries to find a specific VirtualServer from the cache store. 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") @@ -110,7 +110,7 @@ func (f *FakeIPVS) GetVirtualServer(serv *utilipvs.VirtualServer) (*utilipvs.Vir return nil, fmt.Errorf("Not found serv: %v", key.String()) } -//GetVirtualServers is a fake implementation +//GetVirtualServers is a fake implementation, it simply returns all VirtualServers in the cache store. func (f *FakeIPVS) GetVirtualServers() ([]*utilipvs.VirtualServer, error) { res := make([]*utilipvs.VirtualServer, 0) for _, svc := range f.Services { @@ -119,7 +119,7 @@ func (f *FakeIPVS) GetVirtualServers() ([]*utilipvs.VirtualServer, error) { return res, nil } -//Flush is a fake implementation +//Flush is a fake implementation, it simply clears the cache store. func (f *FakeIPVS) Flush() error { // directly drop old data f.Services = nil @@ -127,7 +127,7 @@ func (f *FakeIPVS) Flush() error { return nil } -//AddRealServer is a fake implementation +//AddRealServer is a fake implementation, it simply creates a RealServer for a VirtualServer in the cache store. 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") @@ -145,7 +145,7 @@ func (f *FakeIPVS) AddRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.Re return nil } -//GetRealServers is a fake implementation +//GetRealServers is a fake implementation, it simply returns all RealServers in the cache store. func (f *FakeIPVS) GetRealServers(serv *utilipvs.VirtualServer) ([]*utilipvs.RealServer, error) { if serv == nil { return nil, fmt.Errorf("Failed to get destination for nil service") @@ -157,11 +157,28 @@ func (f *FakeIPVS) GetRealServers(serv *utilipvs.VirtualServer) ([]*utilipvs.Rea return f.Destinations[key], nil } -//DeleteRealServer is a fake implementation -func (*FakeIPVS) DeleteRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error { +//DeleteRealServer is a fake implementation, it deletes the real server in the cache store. +func (f *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") } + key := toServiceKey(serv) + if _, ok := f.Services[key]; !ok { + return fmt.Errorf("Failed to delete destination for service %v, service not found", key.String()) + } + dests := f.Destinations[key] + var i int + for i = range dests { + if dests[i].Equal(dest) { + break + } + } + // Not Found + if i >= len(f.Destinations[key]) { + return fmt.Errorf("Failed to delete real server for service %v, real server not found", key.String()) + } + // Delete one element + f.Destinations[key] = append(f.Destinations[key][:i], f.Destinations[key][i+1:]...) return nil } diff --git a/pkg/util/ipvs/testing/fake_test.go b/pkg/util/ipvs/testing/fake_test.go new file mode 100644 index 0000000000..ea9d0a1950 --- /dev/null +++ b/pkg/util/ipvs/testing/fake_test.go @@ -0,0 +1,149 @@ +/* +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 ( + "net" + "testing" + + utilipvs "k8s.io/kubernetes/pkg/util/ipvs" +) + +func TestVirtualServer(t *testing.T) { + // Initialize + fake := NewFake() + // Add a virtual server + vs1 := &utilipvs.VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Port: uint16(80), + Protocol: string("TCP"), + } + err := fake.AddVirtualServer(vs1) + if err != nil { + t.Errorf("Fail to add virutal server, error: %v", err) + } + // Get a specific virtual server + got1, err := fake.GetVirtualServer(vs1) + if err != nil { + t.Errorf("Fail to get virutal server, error: %v", err) + } + if !vs1.Equal(got1) { + t.Errorf("Expect virtual server: %v, got: %v", vs1, got1) + } + // Add another virtual server + vs2 := &utilipvs.VirtualServer{ + Address: net.ParseIP("10::40"), + Port: uint16(8080), + Protocol: string("UDP"), + } + err = fake.AddVirtualServer(vs2) + if err != nil { + t.Errorf("Unexpected error when add virutal server, error: %v", err) + } + // List all virtual servers + list, err := fake.GetVirtualServers() + if err != nil { + t.Errorf("Fail to list virutal servers, error: %v", err) + } + if len(list) != 2 { + t.Errorf("Expect 2 virutal servers, got: %d", len(list)) + } + // Delete a virtual server + err = fake.DeleteVirtualServer(vs1) + if err != nil { + t.Errorf("Fail to delete virutal server: %v, error: %v", vs1, err) + } + // Check the deleted virtual server no longer exists + got, _ := fake.GetVirtualServer(vs1) + if got != nil { + t.Errorf("Expect nil, got: %v", got) + } + // Flush all virtual servers + err = fake.Flush() + if err != nil { + t.Errorf("Fail to flush virutal servers, error: %v", err) + } + // List all virtual servers + list, err = fake.GetVirtualServers() + if err != nil { + t.Errorf("Fail to list virutal servers, error: %v", err) + } + if len(list) != 0 { + t.Errorf("Expect 0 virutal servers, got: %d", len(list)) + } +} + +func TestRealServer(t *testing.T) { + // Initialize + fake := NewFake() + // Add a virtual server + vs := &utilipvs.VirtualServer{ + Address: net.ParseIP("10.20.30.40"), + Port: uint16(80), + Protocol: string("TCP"), + } + err := fake.AddVirtualServer(vs) + if err != nil { + t.Errorf("Fail to add virutal server, error: %v", err) + } + // Add a real server to the virtual server + rs1 := &utilipvs.RealServer{ + Address: net.ParseIP("172.16.2.1"), + Port: uint16(8080), + Weight: 1, + } + err = fake.AddRealServer(vs, rs1) + if err != nil { + t.Errorf("Fail to add real server, error: %v", err) + } + // Add another real server to the virtual server + rs2 := &utilipvs.RealServer{ + Address: net.ParseIP("172.16.3.2"), + Port: uint16(8080), + Weight: 2, + } + err = fake.AddRealServer(vs, rs2) + if err != nil { + t.Errorf("Fail to add real server, error: %v", err) + } + // List all real servers of the virtual server + list, err := fake.GetRealServers(vs) + if err != nil { + t.Errorf("Fail to get real servers of the virtual server, error: %v", err) + } + if len(list) != 2 { + t.Errorf("Expect 2 virutal servers, got: %d", len(list)) + } + // Delete a real server of the virtual server + err = fake.DeleteRealServer(vs, rs2) + list, err = fake.GetRealServers(vs) + if err != nil { + t.Errorf("Fail to get real servers of the virtual server, error: %v", err) + } + if len(list) != 1 { + t.Errorf("Expect 1 real server, got: %d", len(list)) + } + // Delete the virtual server + err = fake.DeleteVirtualServer(vs) + if err != nil { + t.Errorf("Fail to delete virtual server, error: %v", err) + } + _, err = fake.GetRealServers(vs) + if err == nil { + t.Errorf("Expect error, got nil") + } +}