feat: disconnect-by-extra-route-dependency (#185)

Co-authored-by: wencaiwulue <895703375@qq.com>
This commit is contained in:
naison
2024-03-03 15:22:26 +08:00
committed by GitHub
parent 0730cb12b7
commit 96845ba37a
4 changed files with 253 additions and 20 deletions

View File

@@ -25,21 +25,20 @@ func (svr *Server) Disconnect(req *rpc.DisconnectRequest, resp rpc.Daemon_Discon
log.SetLevel(log.InfoLevel)
switch {
case req.GetAll():
for i := len(svr.secondaryConnect) - 1; i >= 0; i-- {
svr.secondaryConnect[i].Cleanup()
}
svr.secondaryConnect = nil
if svr.connect != nil {
svr.connect.Cleanup()
}
svr.connect = nil
svr.t = time.Time{}
if svr.clone != nil {
_ = svr.clone.Cleanup()
}
svr.clone = nil
connects := handler.Connects(svr.secondaryConnect).Append(svr.connect)
for _, connect := range connects.Sort() {
if connect != nil {
connect.Cleanup()
}
}
svr.secondaryConnect = nil
svr.connect = nil
svr.t = time.Time{}
case req.ID != nil && req.GetID() == 0:
if svr.connect != nil {
svr.connect.Cleanup()

View File

@@ -7,6 +7,7 @@ import (
"github.com/wencaiwulue/kubevpn/v2/pkg/daemon/rpc"
"github.com/wencaiwulue/kubevpn/v2/pkg/dns"
"github.com/wencaiwulue/kubevpn/v2/pkg/handler"
)
func (svr *Server) Quit(req *rpc.QuitRequest, resp rpc.Daemon_QuitServer) error {
@@ -17,15 +18,6 @@ func (svr *Server) Quit(req *rpc.QuitRequest, resp rpc.Daemon_QuitServer) error
log.SetOutput(io.MultiWriter(newQuitWarp(resp), svr.LogFile))
log.SetLevel(log.InfoLevel)
for i := len(svr.secondaryConnect) - 1; i >= 0; i-- {
log.Info("quit: cleanup connection")
svr.secondaryConnect[i].Cleanup()
}
if svr.connect != nil {
log.Info("quit: cleanup connection")
svr.connect.Cleanup()
}
if svr.clone != nil {
log.Info("quit: cleanup clone")
err := svr.clone.Cleanup()
@@ -34,6 +26,14 @@ func (svr *Server) Quit(req *rpc.QuitRequest, resp rpc.Daemon_QuitServer) error
}
}
connects := handler.Connects(svr.secondaryConnect).Append(svr.connect)
for _, conn := range connects.Sort() {
log.Info("quit: cleanup connection")
if conn != nil {
conn.Cleanup()
}
}
dns.CleanupHosts()
// last step is to quit GRPC server

89
pkg/handler/sort.go Normal file
View File

@@ -0,0 +1,89 @@
package handler
import (
"net"
"sort"
)
type Connects []*ConnectOptions
func (s Connects) Len() int {
return len(s)
}
func (s Connects) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Connects) Append(options *ConnectOptions) Connects {
if options != nil {
return append(s, options)
}
return s
}
// Less ...
/**
assume: clusterA and clusterB in same VPC network, but only clusterA api-server have public ip,
we need access clusterB via clusterA network.
steps:
- connect to clusterA with options --extra-cidr or --extra-domain (which container clusterB api-server address)
- connect to clusterB
when we disconnect from all:
first, we need to disconnect clusterB
second, disconnect clusterA
*/
func (s Connects) Less(i, j int) bool {
a := s[i]
b := s[j]
if a == nil {
return true
}
var containsFunc = func(cidr *net.IPNet, ips []net.IP) bool {
for _, ip := range ips {
if !ip.IsLoopback() && cidr.Contains(ip) {
return true
}
}
return false
}
for _, extraCIDR := range b.ExtraRouteInfo.ExtraCIDR {
ip, cidr, err := net.ParseCIDR(extraCIDR)
if err != nil {
continue
}
if containsFunc(cidr, a.apiServerIPs) {
return true
}
for _, p := range a.apiServerIPs {
if ip.Equal(p) {
return true
}
}
}
for _, entry := range b.extraHost {
ip := net.ParseIP(entry.IP)
if ip == nil || ip.IsLoopback() {
continue
}
for _, p := range a.apiServerIPs {
if ip.Equal(p) {
return true
}
}
}
return false
}
// Sort ...
// base order: first connect last disconnect
// sort by dependency
func (s Connects) Sort() Connects {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
sort.Stable(s)
return s
}

145
pkg/handler/sort_test.go Normal file
View File

@@ -0,0 +1,145 @@
package handler
import (
"net"
"reflect"
"testing"
"github.com/wencaiwulue/kubevpn/v2/pkg/dns"
)
func TestSortConnect(t *testing.T) {
tests := []struct {
connects Connects
expectedOrder []string
howToGetOrder func(connects []*ConnectOptions) []string
}{
{
connects: []*ConnectOptions{
{
Namespace: "clusterA",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"192.168.31.1/32"},
},
apiServerIPs: []net.IP{net.ParseIP("172.21.0.12")},
extraHost: nil,
},
{
Namespace: "clusterB",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"10.16.31.9/32"},
},
apiServerIPs: []net.IP{net.ParseIP("192.168.31.1")},
extraHost: nil,
},
},
expectedOrder: []string{"clusterB", "clusterA"},
howToGetOrder: func(connects []*ConnectOptions) []string {
var order []string
for _, connect := range connects {
order = append(order, connect.Namespace)
}
return order
},
},
{
connects: []*ConnectOptions{
{
Namespace: "clusterA",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"192.168.31.2/32"},
},
apiServerIPs: []net.IP{net.ParseIP("172.21.0.12")},
extraHost: []dns.Entry{{
IP: "192.168.31.1",
}},
},
{
Namespace: "clusterB",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"10.16.31.9/32"},
},
apiServerIPs: []net.IP{net.ParseIP("192.168.31.1")},
extraHost: nil,
},
},
expectedOrder: []string{"clusterB", "clusterA"},
howToGetOrder: func(connects []*ConnectOptions) []string {
var order []string
for _, connect := range connects {
order = append(order, connect.Namespace)
}
return order
},
},
{
connects: []*ConnectOptions{
{
Namespace: "clusterA",
ExtraRouteInfo: ExtraRouteInfo{},
apiServerIPs: []net.IP{net.ParseIP("192.168.31.100")},
extraHost: nil,
},
{
Namespace: "clusterB",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"192.168.31.2/32"},
},
apiServerIPs: []net.IP{net.ParseIP("172.21.0.12")},
extraHost: []dns.Entry{{
IP: "192.168.31.1",
}},
},
},
expectedOrder: []string{"clusterB", "clusterA"},
howToGetOrder: func(connects []*ConnectOptions) []string {
var order []string
for _, connect := range connects {
order = append(order, connect.Namespace)
}
return order
},
},
{
connects: []*ConnectOptions{
{
Namespace: "clusterA",
ExtraRouteInfo: ExtraRouteInfo{},
apiServerIPs: []net.IP{net.ParseIP("192.168.31.100")},
extraHost: nil,
},
{
Namespace: "clusterB",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"192.168.31.1/32"},
},
apiServerIPs: []net.IP{net.ParseIP("172.21.0.12")},
extraHost: nil,
},
{
Namespace: "clusterC",
ExtraRouteInfo: ExtraRouteInfo{
ExtraCIDR: []string{"10.16.31.9/32"},
},
apiServerIPs: []net.IP{net.ParseIP("192.168.31.1")},
extraHost: nil,
},
},
expectedOrder: []string{"clusterC", "clusterB", "clusterA"},
howToGetOrder: func(connects []*ConnectOptions) []string {
var order []string
for _, connect := range connects {
order = append(order, connect.Namespace)
}
return order
},
},
}
for i, test := range tests {
order := test.howToGetOrder(test.connects.Sort())
equal := reflect.DeepEqual(order, test.expectedOrder)
if !equal {
t.Fatalf("failed to sort conntions round %d, expected: %v, real: %v", i+1, test.expectedOrder, order)
}
}
}