mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
feat: disconnect-by-extra-route-dependency (#185)
Co-authored-by: wencaiwulue <895703375@qq.com>
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
89
pkg/handler/sort.go
Normal 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
145
pkg/handler/sort_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user