Skip to content

Commit 03f32ff

Browse files
committed
initial version of traffic duplicator
1 parent 9327bd6 commit 03f32ff

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

scripts/traffic-duplicator/example.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
echo "http://localhost:4041/ingest"
4+
echo "http://localhost:4042"
5+
echo "http://localhost:4043"
6+
echo "http://localhost:4044 .*rbspy.*"

scripts/traffic-duplicator/main.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"context"
7+
"flag"
8+
"io"
9+
"io/ioutil"
10+
"net/http"
11+
"net/url"
12+
"os/exec"
13+
"regexp"
14+
"strings"
15+
"sync"
16+
"time"
17+
18+
"github.com/sirupsen/logrus"
19+
)
20+
21+
type target struct {
22+
url *url.URL
23+
matcher *regexp.Regexp
24+
}
25+
26+
var (
27+
// input flags
28+
bindAddr string
29+
logLevel string
30+
targetsPath string
31+
32+
// list of upstream targets
33+
targetsMutex sync.RWMutex
34+
targets []target
35+
)
36+
37+
func main() {
38+
flag.StringVar(&bindAddr, "bind-addr", ":4040", "bind address for http server")
39+
flag.StringVar(&logLevel, "log-level", "info", "log level")
40+
flag.StringVar(&targetsPath, "targets-path", "./generate-targets.sh", "path to a script that generates upstream targets")
41+
flag.Parse()
42+
43+
setupLogging()
44+
go updateTargets()
45+
startProxy()
46+
}
47+
48+
func setupLogging() {
49+
l, err := logrus.ParseLevel(logLevel)
50+
if err != nil {
51+
logrus.Fatal(err)
52+
}
53+
logrus.SetLevel(l)
54+
}
55+
56+
func startProxy() {
57+
logrus.WithFields(logrus.Fields{
58+
"bind-addr": bindAddr,
59+
"targets-path": targetsPath,
60+
}).Info("config")
61+
62+
err := http.ListenAndServe(bindAddr, http.HandlerFunc(handleConn))
63+
logrus.WithError(err).WithField("bindAddr", bindAddr).Error("error listening")
64+
}
65+
66+
func handleConn(w http.ResponseWriter, r *http.Request) {
67+
b, err := ioutil.ReadAll(r.Body)
68+
if err != nil {
69+
logrus.WithError(err).Error("failed to read body")
70+
}
71+
72+
targetsMutex.RLock()
73+
targetsCopy := make([]target, len(targets))
74+
copy(targetsCopy, targets)
75+
targetsMutex.RUnlock()
76+
77+
for _, t := range targetsCopy {
78+
appName := r.URL.Query().Get("name")
79+
if t.matcher.MatchString(appName) {
80+
logrus.WithField("target", t).Debug("uploading to upstream")
81+
reader := bytes.NewReader(b)
82+
83+
r.URL.Scheme = t.url.Scheme
84+
r.URL.Host = t.url.Host
85+
86+
resp, err := http.Post(r.URL.String(), r.Header.Get("Content-Type"), reader)
87+
logrus.WithField("resp", resp).Debug("response")
88+
if err != nil {
89+
logrus.WithError(err).WithField("target", t).Error("failed to upload to target")
90+
}
91+
}
92+
}
93+
}
94+
95+
func updateTargets() {
96+
for {
97+
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
98+
cmd := exec.CommandContext(ctx, targetsPath)
99+
buf := bytes.Buffer{}
100+
cmd.Stdout = &buf
101+
err := cmd.Run()
102+
if err != nil {
103+
logrus.WithError(err).Error("failed to generate targets")
104+
}
105+
targetsMutex.Lock()
106+
targets = generateTargets(bytes.NewReader(buf.Bytes()))
107+
logrus.Debug("new targets:")
108+
for _, t := range targets {
109+
logrus.Debugf("* %s %s", t.url, t.matcher)
110+
}
111+
targetsMutex.Unlock()
112+
time.Sleep(10 * time.Second)
113+
}
114+
}
115+
116+
func generateTargets(r io.Reader) []target {
117+
var targets []target
118+
scanner := bufio.NewScanner(r)
119+
for scanner.Scan() {
120+
line := strings.TrimSpace(scanner.Text())
121+
arr := strings.SplitN(line, " ", 2)
122+
if len(arr) < 2 {
123+
arr = append(arr, ".*")
124+
}
125+
126+
url, err := url.ParseRequestURI(arr[0])
127+
if err != nil {
128+
continue
129+
}
130+
matcher, err := regexp.Compile(arr[1])
131+
if err != nil {
132+
continue
133+
}
134+
targets = append(targets, target{
135+
url: url,
136+
matcher: matcher,
137+
})
138+
}
139+
return targets
140+
}

0 commit comments

Comments
 (0)