Skip to content

Commit

Permalink
Add support to provide multiple service rules directly.
Browse files Browse the repository at this point in the history
  • Loading branch information
dariopb committed Nov 5, 2023
1 parent 8dc7c72 commit b038350
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 1 deletion.
16 changes: 15 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/goreverselb/server.go",
"program": "${workspaceFolder}/cmd/goreverselb",
"env": {
"LOGLEVEL" : "debug",
"TOKEN" : "1234",
Expand All @@ -37,6 +37,20 @@
},
"args": [ "tunnel" ]
},
{
"name": "Debug servicegroup",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/goreverselb",
"env": {
"LOGLEVEL" : "debug",
"TOKEN" : "xxxx",
"LB_API_ENDPOINT" : "xxxx",
"LB_SERVICE_GROUP_JSON" : "{\"srv-1234\":{\"name\":\"srv-1234\",\"ports\":[{\"port\":8000,\"protocol\":\"tcp\"}],\"backendIPs\":[\"127.0.0.1\"],\"deleted\":false}}",
},
"args": [ "tunnelgroup" ]
},
{
"name": "Debug proxy",
"type": "go",
Expand Down
28 changes: 28 additions & 0 deletions cmd/goreverselb/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var natsport int

// client
var lbapiendpoint string
var servicemapjson string
var serviceendpoint string
var insecuretls bool
var wraptls bool
Expand Down Expand Up @@ -209,6 +210,33 @@ func main() {
},
},
},
{
Name: "tunnelgroup",
Usage: "creates multiple ingress tunnels",
Action: servicegroup,

Flags: []cli.Flag{
&cli.StringFlag{
Name: "apiendpoint",
Aliases: []string{"e"},
Value: "",
Usage: "API endpoint in the form: hostname:port",
EnvVars: []string{"LB_API_ENDPOINT"},
Destination: &lbapiendpoint,
Required: true,
},
&cli.StringFlag{
Name: "servicegroup",
Aliases: []string{"g"},
Value: "",
DefaultText: "",
Usage: "service group json: like: '{\"ssh1\":{\"name\":\"ssh1\",\"ports\":[{\"port\":8000,\"protocol\":\"tcp\",\"targetPort\":22}],\"backendIPs\":[\"127.0.0.1\"],\"deleted\":false}}'",
EnvVars: []string{"LB_SERVICE_GROUP_JSON"},
Destination: &servicemapjson,
Required: true,
},
},
},
{
Name: "stdinproxy",
//Aliases: []string{"tunnel"},
Expand Down
47 changes: 47 additions & 0 deletions cmd/goreverselb/servicegroup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"os"
"os/signal"
"syscall"

tunnel "github.com/dariopb/goreverselb/pkg"
"github.com/urfave/cli/v2"

log "github.com/sirupsen/logrus"
)

func servicegroup(ctx *cli.Context) error {
printVersion()

loglevel := log.DebugLevel
if l, err := log.ParseLevel(loglevelstr); err == nil {
loglevel = l
}

//log.AddHook(ProcessCounter)
//log.SetFormatter(&log.TextFormatter{ForceColors: true})
log.SetFormatter(&log.TextFormatter{
//DisableColors: true,
FullTimestamp: true,
})
log.SetLevel(loglevel)
log.SetOutput(os.Stdout)

tsg, err := tunnel.NewMuxTunnelClientServiceGroup(lbapiendpoint, token)
if err != nil {
log.Fatalf("failed to start new tunnel service group: ", err)
}

err = tsg.ReconcileServiceGroupFromJSON(servicemapjson)
if err != nil {
log.Fatalf("failed to reconcile service group: ", err)
}

c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

<-c

return nil
}
9 changes: 9 additions & 0 deletions docker/Dockerfile-alpine-tunnelgroup.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM alpine

WORKDIR /

COPY goreverselb /goreverselb

EXPOSE 9999

CMD ["/goreverselb", "tunnelgroup"]
10 changes: 10 additions & 0 deletions docker/generateDocker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,13 @@ docker tag dariob/reverselb-alpine dariob/reverselb-alpine:latest
docker push dariob/reverselb-alpine:latest
docker push dariob/reverselb-alpine:0.1

# alpine-tunnelgroup
docker build -f docker/Dockerfile-alpine-tunnelgroup.txt -t dariob/reverselb-tunnelgroup .
docker tag dariob/reverselb-tunnelgroup dariob/reverselb-tunnelgroup:0.1
docker tag dariob/reverselb-tunnelgroup dariob/reverselb-tunnelgroup:latest
docker push dariob/reverselb-tunnelgroup:latest
docker push dariob/reverselb-tunnelgroup:0.1

# Run
docker run --rm -e LOGLEVEL=debug -e TOKEN=$TOKEN -e LB_API_ENDPOINT=api.reverselb.com:9000 -e LB_SERVICE_GROUP_JSON='{"ssh1":{"name":"ssh1","ports":[{"port":8000,"protocol":"tcp","targetPort":22}],"backendIPs":["172.17.0.1"],"deleted":false}}' dariob/reverselb-tunnelgroup

175 changes: 175 additions & 0 deletions pkg/muxtunnelClientServiceGroup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package tunnel

import (
"encoding/json"
"fmt"
"reflect"
"sync"

log "github.com/sirupsen/logrus"
)

type MuxTunnelClientServiceGroup struct {
apiEndpoint string
token string

ServiceMap map[string]*ServiceInfo
tunnels map[string]map[string]*MuxTunnelClient

mtx sync.Mutex
}

type ServiceInfo struct {
Name string `json:"name"`
Ports []PortData `json:"ports"`
BackendIPs []string `json:"backendIPs"`

Deleted bool `json:"deleted"`

tunnelEndpointAPI string
token string
}

type PortData struct {
Port int `json:"port"`
Protocol string `json:"protocol"`

TargetPort int `json:"targetPort"`
}

// NewMuxTunnelClientServiceGroup creates a group of multiple services/clients.
func NewMuxTunnelClientServiceGroup(apiEndpoint string, token string) (*MuxTunnelClientServiceGroup, error) {
var err error

log.Infof("NewMuxTunnelClientServiceGroup: on %s", apiEndpoint)
c := &MuxTunnelClientServiceGroup{
apiEndpoint: apiEndpoint,
token: token,

ServiceMap: make(map[string]*ServiceInfo),
tunnels: make(map[string]map[string]*MuxTunnelClient),
}

return c, err
}

func (c *MuxTunnelClientServiceGroup) reconcileTunnels(srv *ServiceInfo) {
var svcTunnelMap map[string]*MuxTunnelClient
ok := false

if srv.tunnelEndpointAPI != "" {
if svcTunnelMap, ok = c.tunnels[srv.Name]; !ok {
svcTunnelMap = make(map[string]*MuxTunnelClient)
c.tunnels[srv.Name] = svcTunnelMap
}
}

portsGone := make(map[string]bool)
for portKey := range svcTunnelMap {
portsGone[portKey] = true
}

if !srv.Deleted {
for _, p := range srv.Ports {
k := fmt.Sprintf("%s-%d", p.Protocol, p.Port)

var err error
var t *MuxTunnelClient
if t, ok = svcTunnelMap[k]; !ok {
td := TunnelData{
ServiceName: srv.Name,
BackendAcceptBacklog: 1,
FrontendData: FrontendData{
Port: p.Port,
},
Token: srv.token,
TargetPort: p.TargetPort,
TargetAddresses: []string{},
}

t, err = NewMuxTunnelClient(srv.tunnelEndpointAPI, td)
if err != nil {
continue
}

svcTunnelMap[k] = t
}

delete(portsGone, k)
belist := t.TargetAddresses()
if !reflect.DeepEqual(srv.BackendIPs, belist) {
log.Info("Updating backend addresses on tunnel", "Service", srv.Name, "IPs", srv.BackendIPs)
t.UpdateTargetAddresses(srv.BackendIPs)
}

beport := t.TargetPort()
if beport != p.TargetPort {
log.Info("Updating backend port on tunnel", "Service", srv.Name, "port", p.TargetPort)
t.UpdateTargetPort(p.TargetPort)
}
}
}

// Removed ports, delete the tunnels
for portKey := range portsGone {
t := svcTunnelMap[portKey]
t.Close()
delete(svcTunnelMap, portKey)
}
}

// ReconcileServiceGroup reconciles the map of services with a new map of services
func (c *MuxTunnelClientServiceGroup) ReconcileServiceGroup(newservices map[string]*ServiceInfo) error {
c.mtx.Lock()
defer c.mtx.Unlock()

srvGone := make(map[string]bool)
for name := range c.ServiceMap {
srvGone[name] = true
}

for _, newservice := range newservices {
svcname := newservice.Name

var srv *ServiceInfo
var ok bool
if srv, ok = c.ServiceMap[svcname]; !ok {
srv = &ServiceInfo{
Name: svcname,
BackendIPs: newservice.BackendIPs,
Ports: newservice.Ports,

tunnelEndpointAPI: c.apiEndpoint,
token: c.token,
}

c.ServiceMap[svcname] = srv
} else {
delete(srvGone, svcname)
}

c.reconcileTunnels(srv)
}

// Removed services, delete the tunnels
for name := range srvGone {
srv := c.ServiceMap[name]
srv.Deleted = true
c.reconcileTunnels(srv)
delete(c.ServiceMap, name)
}

return nil
}

// ReconcileServiceGroupFromJSON reconciles the map of services with a new map of services
// {"name":"srv-1234","ports":[{"port":8000,"protocol":"tcp"}],"backendIPs":["127.0.0.1"],"deleted":false}
func (c *MuxTunnelClientServiceGroup) ReconcileServiceGroupFromJSON(jsonstr string) error {
var newservices map[string]*ServiceInfo
err := json.Unmarshal([]byte(jsonstr), &newservices)
if err != nil {
return err
}

return c.ReconcileServiceGroup(newservices)
}

0 comments on commit b038350

Please sign in to comment.