mirror of https://github.com/coder/coder.git
fix: update conn derpmap every 5s in single tailnet (#9176)
This commit is contained in:
parent
53de47d4c8
commit
f35423c041
|
@ -11976,6 +11976,9 @@ const docTemplate = `{
|
|||
"app_security_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"derp_map": {
|
||||
"$ref": "#/definitions/tailcfg.DERPMap"
|
||||
},
|
||||
"derp_mesh_key": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -10937,6 +10937,9 @@
|
|||
"app_security_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"derp_map": {
|
||||
"$ref": "#/definitions/tailcfg.DERPMap"
|
||||
},
|
||||
"derp_mesh_key": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -404,7 +404,7 @@ func New(options *Options) *API {
|
|||
api.agentProvider, err = NewServerTailnet(api.ctx,
|
||||
options.Logger,
|
||||
options.DERPServer,
|
||||
options.BaseDERPMap,
|
||||
api.DERPMap,
|
||||
func(context.Context) (tailnet.MultiAgentConn, error) {
|
||||
return (*api.TailnetCoordinator.Load()).ServeMultiAgent(uuid.New()), nil
|
||||
},
|
||||
|
|
|
@ -44,15 +44,16 @@ func NewServerTailnet(
|
|||
ctx context.Context,
|
||||
logger slog.Logger,
|
||||
derpServer *derp.Server,
|
||||
derpMap *tailcfg.DERPMap,
|
||||
derpMapFn func() *tailcfg.DERPMap,
|
||||
getMultiAgent func(context.Context) (tailnet.MultiAgentConn, error),
|
||||
cache *wsconncache.Cache,
|
||||
traceProvider trace.TracerProvider,
|
||||
) (*ServerTailnet, error) {
|
||||
logger = logger.Named("servertailnet")
|
||||
originalDerpMap := derpMapFn()
|
||||
conn, err := tailnet.NewConn(&tailnet.Options{
|
||||
Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)},
|
||||
DERPMap: derpMap,
|
||||
DERPMap: originalDerpMap,
|
||||
Logger: logger,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -60,9 +61,32 @@ func NewServerTailnet(
|
|||
}
|
||||
|
||||
serverCtx, cancel := context.WithCancel(ctx)
|
||||
derpMapUpdaterClosed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(derpMapUpdaterClosed)
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-serverCtx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
|
||||
newDerpMap := derpMapFn()
|
||||
if !tailnet.CompareDERPMaps(originalDerpMap, newDerpMap) {
|
||||
conn.SetDERPMap(newDerpMap)
|
||||
originalDerpMap = newDerpMap
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
tn := &ServerTailnet{
|
||||
ctx: serverCtx,
|
||||
cancel: cancel,
|
||||
derpMapUpdaterClosed: derpMapUpdaterClosed,
|
||||
logger: logger,
|
||||
tracer: traceProvider.Tracer(tracing.TracerName),
|
||||
conn: conn,
|
||||
|
@ -237,8 +261,9 @@ func (s *ServerTailnet) reinitCoordinator() {
|
|||
}
|
||||
|
||||
type ServerTailnet struct {
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
derpMapUpdaterClosed chan struct{}
|
||||
|
||||
logger slog.Logger
|
||||
tracer trace.Tracer
|
||||
|
@ -403,5 +428,6 @@ func (s *ServerTailnet) Close() error {
|
|||
_ = s.cache.Close()
|
||||
_ = s.conn.Close()
|
||||
s.transport.CloseIdleConnections()
|
||||
<-s.derpMapUpdaterClosed
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"tailscale.com/tailcfg"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"cdr.dev/slog/sloggers/slogtest"
|
||||
|
@ -230,7 +231,7 @@ func setupAgent(t *testing.T, agentAddresses []netip.Prefix) (uuid.UUID, agent.A
|
|||
context.Background(),
|
||||
logger,
|
||||
derpServer,
|
||||
manifest.DERPMap,
|
||||
func() *tailcfg.DERPMap { return manifest.DERPMap },
|
||||
func(context.Context) (tailnet.MultiAgentConn, error) { return coord.ServeMultiAgent(uuid.New()), nil },
|
||||
cache,
|
||||
trace.NewNoopTracerProvider(),
|
||||
|
|
|
@ -7724,6 +7724,65 @@ _None_
|
|||
```json
|
||||
{
|
||||
"app_security_key": "string",
|
||||
"derp_map": {
|
||||
"homeParams": {
|
||||
"regionScore": {
|
||||
"property1": 0,
|
||||
"property2": 0
|
||||
}
|
||||
},
|
||||
"omitDefaultRegions": true,
|
||||
"regions": {
|
||||
"property1": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"canPort80": true,
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
},
|
||||
"property2": {
|
||||
"avoid": true,
|
||||
"embeddedRelay": true,
|
||||
"nodes": [
|
||||
{
|
||||
"canPort80": true,
|
||||
"certName": "string",
|
||||
"derpport": 0,
|
||||
"forceHTTP": true,
|
||||
"hostName": "string",
|
||||
"insecureForTests": true,
|
||||
"ipv4": "string",
|
||||
"ipv6": "string",
|
||||
"name": "string",
|
||||
"regionID": 0,
|
||||
"stunonly": true,
|
||||
"stunport": 0,
|
||||
"stuntestIP": "string"
|
||||
}
|
||||
],
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"derp_mesh_key": "string",
|
||||
"derp_region_id": 0,
|
||||
"sibling_replicas": [
|
||||
|
@ -7745,6 +7804,7 @@ _None_
|
|||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------ | --------------------------------------------- | -------- | ------------ | -------------------------------------------------------------------------------------- |
|
||||
| `app_security_key` | string | false | | |
|
||||
| `derp_map` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | |
|
||||
| `derp_mesh_key` | string | false | | |
|
||||
| `derp_region_id` | integer | false | | |
|
||||
| `sibling_replicas` | array of [codersdk.Replica](#codersdkreplica) | false | | Sibling replicas is a list of all other replicas of the proxy that have not timed out. |
|
||||
|
|
|
@ -720,6 +720,7 @@ func (api *API) workspaceProxyRegister(rw http.ResponseWriter, r *http.Request)
|
|||
AppSecurityKey: api.AppSecurityKey.String(),
|
||||
DERPMeshKey: api.DERPServer.MeshKey(),
|
||||
DERPRegionID: regionID,
|
||||
DERPMap: api.AGPL.DERPMap(),
|
||||
SiblingReplicas: siblingsRes,
|
||||
})
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"golang.org/x/xerrors"
|
||||
"tailscale.com/derp"
|
||||
"tailscale.com/derp/derphttp"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
|
||||
"cdr.dev/slog"
|
||||
|
@ -119,7 +120,8 @@ type Server struct {
|
|||
SDKClient *wsproxysdk.Client
|
||||
|
||||
// DERP
|
||||
derpMesh *derpmesh.Mesh
|
||||
derpMesh *derpmesh.Mesh
|
||||
latestDERPMap *tailcfg.DERPMap
|
||||
|
||||
// Used for graceful shutdown. Required for the dialer.
|
||||
ctx context.Context
|
||||
|
@ -239,17 +241,14 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
|
|||
return nil, xerrors.Errorf("parse app security key: %w", err)
|
||||
}
|
||||
|
||||
connInfo, err := client.SDKClient.WorkspaceAgentConnectionInfoGeneric(ctx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get derpmap: %w", err)
|
||||
}
|
||||
|
||||
var agentProvider workspaceapps.AgentProvider
|
||||
if opts.Experiments.Enabled(codersdk.ExperimentSingleTailnet) {
|
||||
stn, err := coderd.NewServerTailnet(ctx,
|
||||
s.Logger,
|
||||
nil,
|
||||
connInfo.DERPMap,
|
||||
func() *tailcfg.DERPMap {
|
||||
return s.latestDERPMap
|
||||
},
|
||||
s.DialCoordinator,
|
||||
wsconncache.New(s.DialWorkspaceAgent, 0),
|
||||
s.TracerProvider,
|
||||
|
@ -456,6 +455,8 @@ func (s *Server) handleRegister(_ context.Context, res wsproxysdk.RegisterWorksp
|
|||
}
|
||||
s.derpMesh.SetAddresses(addresses, false)
|
||||
|
||||
s.latestDERPMap = res.DERPMap
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
"nhooyr.io/websocket"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/util/singleflight"
|
||||
|
||||
"cdr.dev/slog"
|
||||
|
@ -206,9 +207,10 @@ type RegisterWorkspaceProxyRequest struct {
|
|||
}
|
||||
|
||||
type RegisterWorkspaceProxyResponse struct {
|
||||
AppSecurityKey string `json:"app_security_key"`
|
||||
DERPMeshKey string `json:"derp_mesh_key"`
|
||||
DERPRegionID int32 `json:"derp_region_id"`
|
||||
AppSecurityKey string `json:"app_security_key"`
|
||||
DERPMeshKey string `json:"derp_mesh_key"`
|
||||
DERPRegionID int32 `json:"derp_region_id"`
|
||||
DERPMap *tailcfg.DERPMap `json:"derp_map"`
|
||||
// SiblingReplicas is a list of all other replicas of the proxy that have
|
||||
// not timed out.
|
||||
SiblingReplicas []codersdk.Replica `json:"sibling_replicas"`
|
||||
|
|
Loading…
Reference in New Issue