@@ -3,10 +3,14 @@ package agent_test
3
3
import (
4
4
"bufio"
5
5
"context"
6
+ "crypto/tls"
6
7
"encoding/json"
7
8
"fmt"
8
9
"io"
9
10
"net"
11
+ "net/http"
12
+ "net/http/httptest"
13
+ "net/netip"
10
14
"os"
11
15
"os/exec"
12
16
"path/filepath"
@@ -17,6 +21,11 @@ import (
17
21
"time"
18
22
19
23
"golang.org/x/xerrors"
24
+ "tailscale.com/derp"
25
+ "tailscale.com/derp/derphttp"
26
+ "tailscale.com/tailcfg"
27
+ "tailscale.com/types/key"
28
+ tslogger "tailscale.com/types/logger"
20
29
21
30
scp "github.com/bramvdbogaerde/go-scp"
22
31
"github.com/google/uuid"
@@ -38,6 +47,7 @@ import (
38
47
"github.com/coder/coder/peerbroker/proto"
39
48
"github.com/coder/coder/provisionersdk"
40
49
"github.com/coder/coder/pty/ptytest"
50
+ "github.com/coder/coder/tailnet"
41
51
"github.com/coder/coder/testutil"
42
52
)
43
53
@@ -423,7 +433,14 @@ func TestAgent(t *testing.T) {
423
433
424
434
t .Run ("Tailscale" , func (t * testing.T ) {
425
435
t .Parallel ()
426
-
436
+ derpMap := runDERPAndStun (t , tailnet .Logger (slogtest .Make (t , nil )))
437
+ conn := setupSSHSession (t , agent.Metadata {
438
+ DERPMap : derpMap ,
439
+ })
440
+ defer conn .Close ()
441
+ output , err := conn .CombinedOutput ("echo test" )
442
+ require .NoError (t , err )
443
+ t .Log (string (output ))
427
444
})
428
445
}
429
446
@@ -469,6 +486,9 @@ func setupSSHSession(t *testing.T, options agent.Metadata) *ssh.Session {
469
486
470
487
func setupAgent (t * testing.T , metadata agent.Metadata , ptyTimeout time.Duration ) agent.Conn {
471
488
client , server := provisionersdk .TransportPipe ()
489
+ tailscale := metadata .DERPMap != nil
490
+ coordinator := tailnet .NewCoordinator ()
491
+ agentID := uuid .New ()
472
492
closer := agent .New (agent.Options {
473
493
FetchMetadata : func (ctx context.Context ) (agent.Metadata , error ) {
474
494
return metadata , nil
@@ -477,6 +497,12 @@ func setupAgent(t *testing.T, metadata agent.Metadata, ptyTimeout time.Duration)
477
497
listener , err := peerbroker .Listen (server , nil )
478
498
return listener , err
479
499
},
500
+ CoordinatorDialer : func (ctx context.Context ) (net.Conn , error ) {
501
+ clientConn , serverConn := net .Pipe ()
502
+ go coordinator .ServeAgent (serverConn , agentID )
503
+ return clientConn , nil
504
+ },
505
+ EnableTailnet : tailscale ,
480
506
Logger : slogtest .Make (t , nil ).Leveled (slog .LevelDebug ),
481
507
ReconnectingPTYTimeout : ptyTimeout ,
482
508
})
@@ -488,6 +514,24 @@ func setupAgent(t *testing.T, metadata agent.Metadata, ptyTimeout time.Duration)
488
514
api := proto .NewDRPCPeerBrokerClient (provisionersdk .Conn (client ))
489
515
stream , err := api .NegotiateConnection (context .Background ())
490
516
assert .NoError (t , err )
517
+ if tailscale {
518
+ conn , err := tailnet .NewConn (& tailnet.Options {
519
+ Addresses : []netip.Prefix {netip .PrefixFrom (tailnet .IP (), 128 )},
520
+ DERPMap : metadata .DERPMap ,
521
+ Logger : slogtest .Make (t , nil ).Named ("tailnet" ),
522
+ })
523
+ require .NoError (t , err )
524
+
525
+ clientConn , serverConn := net .Pipe ()
526
+ go coordinator .ServeClient (serverConn , uuid .New (), agentID )
527
+ sendNode , _ := tailnet .ServeCoordinator (clientConn , func (node []* tailnet.Node ) error {
528
+ return conn .UpdateNodes (node )
529
+ })
530
+ conn .SetNodeCallback (sendNode )
531
+ return & agent.TailnetConn {
532
+ Conn : conn ,
533
+ }
534
+ }
491
535
conn , err := peerbroker .Dial (stream , []webrtc.ICEServer {}, & peer.ConnOptions {
492
536
Logger : slogtest .Make (t , nil ),
493
537
})
@@ -532,3 +576,53 @@ func assertWritePayload(t *testing.T, w io.Writer, payload []byte) {
532
576
assert .NoError (t , err , "write payload" )
533
577
assert .Equal (t , len (payload ), n , "payload length does not match" )
534
578
}
579
+
580
+ func runDERPAndStun (t * testing.T , logf tslogger.Logf ) (derpMap * tailcfg.DERPMap ) {
581
+ d := derp .NewServer (key .NewNode (), logf )
582
+ server := httptest .NewUnstartedServer (derphttp .Handler (d ))
583
+ server .Config .ErrorLog = tslogger .StdLogger (logf )
584
+ server .Config .TLSNextProto = make (map [string ]func (* http.Server , * tls.Conn , http.Handler ))
585
+ server .StartTLS ()
586
+
587
+ // stunAddr, stunCleanup := stuntest.ServeWithPacketListener(t, nettype.Std{})
588
+ t .Cleanup (func () {
589
+ server .CloseClientConnections ()
590
+ server .Close ()
591
+ d .Close ()
592
+ // stunCleanup()
593
+ })
594
+
595
+ tcpAddr , ok := server .Listener .Addr ().(* net.TCPAddr )
596
+ if ! ok {
597
+ t .FailNow ()
598
+ }
599
+
600
+ return & tailcfg.DERPMap {
601
+ Regions : map [int ]* tailcfg.DERPRegion {
602
+ 1 : {
603
+ RegionID : 1 ,
604
+ RegionCode : "test" ,
605
+ RegionName : "Testlandia" ,
606
+ Nodes : []* tailcfg.DERPNode {
607
+ {
608
+ Name : "t1" ,
609
+ RegionID : 1 ,
610
+ HostName : "stun.l.google.com" ,
611
+ DERPPort : - 1 ,
612
+ STUNPort : 19302 ,
613
+ STUNOnly : true ,
614
+ },
615
+ {
616
+ Name : "t2" ,
617
+ RegionID : 1 ,
618
+ IPv4 : "127.0.0.1" ,
619
+ IPv6 : "none" ,
620
+ STUNPort : - 1 ,
621
+ DERPPort : tcpAddr .Port ,
622
+ InsecureForTests : true ,
623
+ },
624
+ },
625
+ },
626
+ },
627
+ }
628
+ }
0 commit comments