Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fed02cd

Browse files
authored
chore: replace cloudflare dev tunnel with frp (#867)
1 parent 42e9956 commit fed02cd

File tree

8 files changed

+222
-374
lines changed

8 files changed

+222
-374
lines changed

.goreleaser.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ before:
1717
builds:
1818
- id: coder-slim
1919
dir: cmd/coder
20-
ldflags: ["-s -w -X github.com/coder/coder/cli/buildinfo.tag={{ .Version }}"]
20+
ldflags:
21+
["-s -w -X github.com/coder/coder/cli/buildinfo.tag={{ .Version }}"]
2122
env: [CGO_ENABLED=0]
2223
goos: [darwin, linux, windows]
2324
goarch: [amd64]
@@ -28,8 +29,9 @@ builds:
2829
2930
- id: coder
3031
dir: cmd/coder
31-
flags: [-tags=embed]
32-
ldflags: ["-s -w -X github.com/coder/coder/cli/buildinfo.tag={{ .Version }}"]
32+
flags: ["-tags=embed"]
33+
ldflags:
34+
["-s -w -X github.com/coder/coder/cli/buildinfo.tag={{ .Version }}"]
3335
env: [CGO_ENABLED=0]
3436
goos: [darwin, linux, windows]
3537
goarch: [amd64, arm64]
@@ -61,4 +63,4 @@ release:
6163
ids: [coder, packages]
6264

6365
snapshot:
64-
name_template: '{{ .Version }}-devel+{{ .ShortCommit }}'
66+
name_template: "{{ .Version }}-devel+{{ .ShortCommit }}"

cli/start.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import (
3232
"github.com/coder/coder/coderd"
3333
"github.com/coder/coder/coderd/database"
3434
"github.com/coder/coder/coderd/database/databasefake"
35+
"github.com/coder/coder/coderd/devtunnel"
3536
"github.com/coder/coder/coderd/gitsshkey"
36-
"github.com/coder/coder/coderd/tunnel"
3737
"github.com/coder/coder/codersdk"
3838
"github.com/coder/coder/provisioner/terraform"
3939
"github.com/coder/coder/provisionerd"
@@ -105,7 +105,13 @@ func start() *cobra.Command {
105105
// If an access URL is specified, always skip tunneling.
106106
skipTunnel = true
107107
}
108-
var tunnelErr <-chan error
108+
109+
var (
110+
tunnelErrChan <-chan error
111+
ctxTunnel, closeTunnel = context.WithCancel(cmd.Context())
112+
)
113+
defer closeTunnel()
114+
109115
// If we're attempting to tunnel in dev-mode, the access URL
110116
// needs to be changed to use the tunnel.
111117
if dev && !skipTunnel {
@@ -124,13 +130,14 @@ func start() *cobra.Command {
124130
return err
125131
}
126132
if err == nil {
127-
accessURL, tunnelErr, err = tunnel.New(cmd.Context(), localURL.String())
133+
accessURL, tunnelErrChan, err = devtunnel.New(ctxTunnel, localURL)
128134
if err != nil {
129135
return xerrors.Errorf("create tunnel: %w", err)
130136
}
131137
}
132138
_, _ = fmt.Fprintln(cmd.ErrOrStderr())
133139
}
140+
134141
validator, err := idtoken.NewValidator(cmd.Context(), option.WithoutAuthentication())
135142
if err != nil {
136143
return err
@@ -263,8 +270,10 @@ func start() *cobra.Command {
263270
case <-cmd.Context().Done():
264271
closeCoderd()
265272
return cmd.Context().Err()
266-
case err := <-tunnelErr:
267-
return err
273+
case err := <-tunnelErrChan:
274+
if err != nil {
275+
return err
276+
}
268277
case err := <-errCh:
269278
closeCoderd()
270279
return err
@@ -328,6 +337,12 @@ func start() *cobra.Command {
328337
spin.Stop()
329338
}
330339

340+
if dev && !skipTunnel {
341+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"Waiting for dev tunnel to close...\n")
342+
closeTunnel()
343+
<-tunnelErrChan
344+
}
345+
331346
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"Waiting for WebSocket connections to close...\n")
332347
shutdownConns()
333348
closeCoderd()

cmd/templater/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"github.com/coder/coder/coderd"
2121
"github.com/coder/coder/coderd/database"
2222
"github.com/coder/coder/coderd/database/databasefake"
23-
"github.com/coder/coder/coderd/tunnel"
23+
"github.com/coder/coder/coderd/devtunnel"
2424
"github.com/coder/coder/codersdk"
2525
"github.com/coder/coder/provisioner/terraform"
2626
"github.com/coder/coder/provisionerd"
@@ -63,7 +63,7 @@ func parse(cmd *cobra.Command, parameters []codersdk.CreateParameterRequest) err
6363
if err != nil {
6464
return err
6565
}
66-
accessURL, errCh, err := tunnel.New(cmd.Context(), srv.URL)
66+
accessURL, errCh, err := devtunnel.New(cmd.Context(), serverURL)
6767
if err != nil {
6868
return err
6969
}

coderd/devtunnel/tunnel.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package devtunnel
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"strconv"
8+
"strings"
9+
10+
frpclient "github.com/fatedier/frp/client"
11+
frpconfig "github.com/fatedier/frp/pkg/config"
12+
frpconsts "github.com/fatedier/frp/pkg/consts"
13+
frplog "github.com/fatedier/frp/pkg/util/log"
14+
frpcrypto "github.com/fatedier/golib/crypto"
15+
"github.com/google/uuid"
16+
"github.com/moby/moby/pkg/namesgenerator"
17+
"golang.org/x/xerrors"
18+
)
19+
20+
// New creates a new tunnel pointing at the URL provided. Once created, it
21+
// returns the external hostname that will resolve to it.
22+
//
23+
// The tunnel will exit when the context provided is canceled.
24+
//
25+
// Upstream connection occurs synchronously through a selfhosted
26+
// https://github.com/fatedier/frp instance. The error channel sends an error
27+
// when the frp client stops.
28+
func New(ctx context.Context, coderurl *url.URL) (string, <-chan error, error) {
29+
frpcrypto.DefaultSalt = "frp"
30+
31+
cfg := frpconfig.GetDefaultClientConf()
32+
cfg.ServerAddr = "frp-tunnel.coder.app"
33+
cfg.ServerPort = 7000
34+
35+
// Ignore all logs from frp.
36+
frplog.InitLog("file", "/dev/null", "error", 0, false)
37+
38+
var (
39+
id = uuid.NewString()
40+
subdomain = strings.ReplaceAll(namesgenerator.GetRandomName(1), "_", "-")
41+
portStr = coderurl.Port()
42+
)
43+
if portStr == "" {
44+
portStr = "80"
45+
}
46+
47+
port, err := strconv.ParseInt(portStr, 10, 64)
48+
if err != nil {
49+
return "", nil, xerrors.Errorf("parse port %q: %w", port, err)
50+
}
51+
52+
httpcfg := map[string]frpconfig.ProxyConf{
53+
id: &frpconfig.HTTPProxyConf{
54+
BaseProxyConf: frpconfig.BaseProxyConf{
55+
ProxyName: id,
56+
ProxyType: frpconsts.HTTPProxy,
57+
UseEncryption: false,
58+
UseCompression: false,
59+
LocalSvrConf: frpconfig.LocalSvrConf{
60+
LocalIP: coderurl.Hostname(),
61+
LocalPort: int(port),
62+
},
63+
},
64+
DomainConf: frpconfig.DomainConf{
65+
SubDomain: subdomain,
66+
},
67+
Locations: []string{""},
68+
},
69+
}
70+
71+
if err := httpcfg[id].CheckForCli(); err != nil {
72+
return "", nil, xerrors.Errorf("check for cli: %w", err)
73+
}
74+
75+
svc, err := frpclient.NewService(cfg, httpcfg, nil, "")
76+
if err != nil {
77+
return "", nil, xerrors.Errorf("create new proxy service: %w", err)
78+
}
79+
80+
ch := make(chan error, 1)
81+
go func() {
82+
err := svc.Run()
83+
ch <- err
84+
close(ch)
85+
}()
86+
go func() {
87+
<-ctx.Done()
88+
svc.Close()
89+
}()
90+
91+
return fmt.Sprintf("https://%s.try.coder.app", subdomain), ch, nil
92+
}

coderd/tunnel/tunnel_test.go renamed to coderd/devtunnel/tunnel_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
package tunnel_test
1+
package devtunnel_test
22

33
import (
44
"context"
55
"net"
66
"net/http"
77
"net/http/httptest"
8-
"os"
8+
"net/url"
99
"testing"
1010
"time"
1111

1212
"github.com/stretchr/testify/require"
1313
"golang.org/x/xerrors"
1414

15-
"github.com/coder/coder/coderd/tunnel"
15+
"github.com/coder/coder/coderd/devtunnel"
1616
)
1717

1818
// The tunnel leaks a few goroutines that aren't impactful to production scenarios.
@@ -22,9 +22,7 @@ import (
2222

2323
func TestTunnel(t *testing.T) {
2424
t.Parallel()
25-
if testing.Short() || os.Getenv("CI") != "" {
26-
// This test has extreme inconsistency in CI.
27-
// It's something with the networking in CI that causes this test to flake.
25+
if testing.Short() {
2826
t.Skip()
2927
return
3028
}
@@ -36,12 +34,16 @@ func TestTunnel(t *testing.T) {
3634

3735
ctx, cancelFunc := context.WithCancel(context.Background())
3836
defer cancelFunc()
39-
url, _, err := tunnel.New(ctx, srv.URL)
37+
38+
srvURL, err := url.Parse(srv.URL)
39+
require.NoError(t, err)
40+
41+
tunURL, _, err := devtunnel.New(ctx, srvURL)
4042
require.NoError(t, err)
41-
t.Log(url)
43+
t.Log(tunURL)
4244

4345
require.Eventually(t, func() bool {
44-
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
46+
req, err := http.NewRequestWithContext(ctx, "GET", tunURL, nil)
4547
require.NoError(t, err)
4648
res, err := http.DefaultClient.Do(req)
4749
var dnsErr *net.DNSError

coderd/tunnel/tunnel.go

Lines changed: 0 additions & 117 deletions
This file was deleted.

0 commit comments

Comments
 (0)