Files
cloudpods/pkg/cloudproxy/agent/ssh/clientset.go
2021-04-06 13:02:14 +08:00

188 lines
4.3 KiB
Go

// Copyright 2019 Yunion
//
// 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 ssh
import (
"context"
ssh_util "yunion.io/x/onecloud/pkg/util/ssh"
)
type epClientSet struct {
cc ssh_util.ClientConfig
clients []*Client
mark bool
}
func (epcs *epClientSet) clearMark() {
epcs.mark = false
}
func (epcs *epClientSet) setMark() {
epcs.mark = true
}
func (epcs *epClientSet) getMark() bool {
return epcs.mark
}
func (epcs *epClientSet) stop(ctx context.Context) {
for _, client := range epcs.clients {
client.Stop(ctx)
}
}
type epClients map[string]*epClientSet // key: epKey
type ClientSet struct {
epClients epClients
}
func NewClientSet() *ClientSet {
cs := &ClientSet{
epClients: epClients{},
}
return cs
}
func (cs *ClientSet) ClearAllMark() {
for _, epcs := range cs.epClients {
epcs.clearMark()
}
}
func (cs *ClientSet) ResetIfChanged(ctx context.Context, epKey string, cc ssh_util.ClientConfig) bool {
epcs, ok := cs.epClients[epKey]
if ok {
if epcs.cc != cc {
epcs.stop(ctx)
delete(cs.epClients, epKey)
cs.AddIfNotExist(ctx, epKey, cc)
return true
}
epcs.setMark()
}
return false
}
func (cs *ClientSet) AddIfNotExist(ctx context.Context, epKey string, cc ssh_util.ClientConfig) bool {
epcs, ok := cs.epClients[epKey]
if !ok {
epcs := &epClientSet{
cc: cc,
}
epcs.setMark()
cs.epClients[epKey] = epcs
return true
}
epcs.setMark()
return false
}
func (cs *ClientSet) ResetUnmarked(ctx context.Context) {
for epKey, epcs := range cs.epClients {
if !epcs.getMark() {
epcs.stop(ctx)
delete(cs.epClients, epKey)
}
}
}
func (cs *ClientSet) ForwardKeySet() ForwardKeySet {
fks := ForwardKeySet{}
for epKey, epcs := range cs.epClients {
for _, client := range epcs.clients {
fks.addByPortMap(epKey, ForwardKeyTypeL, client.localForwards)
fks.addByPortMap(epKey, ForwardKeyTypeR, client.remoteForwards)
}
}
return fks
}
func (cs *ClientSet) LocalForward(ctx context.Context, epKey string, req LocalForwardReq) {
client, created := cs.getOrCreateClient(epKey, ForwardKeyTypeL)
if created {
go client.Start(ctx)
}
client.LocalForward(ctx, req)
}
func (cs *ClientSet) RemoteForward(ctx context.Context, epKey string, req RemoteForwardReq) {
client, created := cs.getOrCreateClient(epKey, ForwardKeyTypeR)
if created {
go client.Start(ctx)
}
client.RemoteForward(ctx, req)
}
func (cs *ClientSet) CloseForward(ctx context.Context, fk ForwardKey) {
client := cs.getClient(fk.EpKey, fk.Type)
if client == nil {
return
}
switch fk.Type {
case ForwardKeyTypeL:
client.LocalForwardClose(ctx, LocalForwardReq{
LocalAddr: fk.KeyAddr,
LocalPort: fk.KeyPort,
})
case ForwardKeyTypeR:
client.RemoteForwardClose(ctx, RemoteForwardReq{
RemoteAddr: fk.KeyAddr,
RemotePort: fk.KeyPort,
})
}
}
/*
func (cs *ClientSet) LocalForwardClose(ctx context.Context, epKey string, req LocalForwardReq) {
client := cs.getClient(epKey, ForwardKeyTypeL)
client.LocalForwardClose(ctx, req)
}
func (cs *ClientSet) RemoteForwardClose(ctx context.Context, epKey string, req RemoteForwardReq) {
client := cs.getClient(epKey, ForwardKeyTypeR)
client.RemoteForwardClose(ctx, req)
}
*/
func (cs *ClientSet) getOrCreateClient(epKey string, typ string) (*Client, bool) {
return cs.getClient_(epKey, typ, true)
}
func (cs *ClientSet) getClient(epKey string, typ string) *Client {
client, _ := cs.getClient_(epKey, typ, false)
return client
}
func (cs *ClientSet) getClient_(epKey string, typ string, create bool) (*Client, bool) {
var client *Client
clients, ok := cs.epClients[epKey]
if !ok || len(clients.clients) == 0 {
if !ok || !create {
return nil, false
}
client = NewClient(&clients.cc)
clients.clients = append(clients.clients, client)
cs.epClients[epKey] = clients
return client, true
} else {
client = clients.clients[0]
return client, false
}
}