Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite8b1a57

Browse files
authored
feat: Add support for VS Code and JetBrains Gateway via SSH (#956)
* Improve CLI documentation* feat: Allow workspace resources to attach multiple agentsThis enables a "kubernetes_pod" to attach multiple agents thatcould be for multiple services. Each agent is required to havea unique name, so SSH syntax is:`coder ssh <workspace>.<agent>`A resource can have zero agents too, they aren't required.* Add tree view* Improve table UI* feat: Allow workspace resources to attach multiple agentsThis enables a "kubernetes_pod" to attach multiple agents thatcould be for multiple services. Each agent is required to havea unique name, so SSH syntax is:`coder ssh <workspace>.<agent>`A resource can have zero agents too, they aren't required.* Rename `tunnel` to `skip-tunnel`This command was `true` by default, which causesa confusing user experience.* Add disclaimer about editing templates* Add help to template create* Improve workspace create flow* Add end-to-end test for config-ssh* Improve testing of config-ssh* Fix workspace list* feat: Add support for VS Code and JetBrains Gateway via SSHThis fixes various bugs that made this not work:- Incorrect max message size in `peer`- Incorrect reader buffer size in `peer`- Lack of SFTP support in `agent`- Lack of direct-tcpip support in `agent`- Misuse of command from session. It should always use the shell- Blocking on SSH session, only allowing one at a timeFixes#833 too.* Fix config-ssh command with socat
1 parentfb9dc4f commite8b1a57

File tree

7 files changed

+75
-49
lines changed

7 files changed

+75
-49
lines changed

‎.github/workflows/coder.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ jobs:
158158
terraform_version:1.1.2
159159
terraform_wrapper:false
160160

161+
-name:Install socat
162+
if:runner.os == 'Linux'
163+
run:sudo apt-get install -y socat
164+
161165
-name:Test with Mock Database
162166
shell:bash
163167
env:

‎agent/agent.go

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"github.com/coder/coder/pty"
2222
"github.com/coder/retry"
2323

24+
"github.com/pkg/sftp"
25+
2426
"github.com/gliderlabs/ssh"
2527
gossh"golang.org/x/crypto/ssh"
2628
"golang.org/x/xerrors"
@@ -121,7 +123,7 @@ func (a *agent) handlePeerConn(ctx context.Context, conn *peer.Conn) {
121123

122124
switchchannel.Protocol() {
123125
case"ssh":
124-
a.sshServer.HandleConn(channel.NetConn())
126+
goa.sshServer.HandleConn(channel.NetConn())
125127
default:
126128
a.options.Logger.Warn(ctx,"unhandled protocol from channel",
127129
slog.F("protocol",channel.Protocol()),
@@ -146,7 +148,10 @@ func (a *agent) init(ctx context.Context) {
146148
sshLogger:=a.options.Logger.Named("ssh-server")
147149
forwardHandler:=&ssh.ForwardedTCPHandler{}
148150
a.sshServer=&ssh.Server{
149-
ChannelHandlers:ssh.DefaultChannelHandlers,
151+
ChannelHandlers:map[string]ssh.ChannelHandler{
152+
"direct-tcpip":ssh.DirectTCPIPHandler,
153+
"session":ssh.DefaultSessionHandler,
154+
},
150155
ConnectionFailedCallback:func(conn net.Conn,errerror) {
151156
sshLogger.Info(ctx,"ssh connection ended",slog.Error(err))
152157
},
@@ -185,61 +190,54 @@ func (a *agent) init(ctx context.Context) {
185190
NoClientAuth:true,
186191
}
187192
},
193+
SubsystemHandlers:map[string]ssh.SubsystemHandler{
194+
"sftp":func(session ssh.Session) {
195+
server,err:=sftp.NewServer(session)
196+
iferr!=nil {
197+
a.options.Logger.Debug(session.Context(),"initialize sftp server",slog.Error(err))
198+
return
199+
}
200+
deferserver.Close()
201+
err=server.Serve()
202+
iferrors.Is(err,io.EOF) {
203+
return
204+
}
205+
a.options.Logger.Debug(session.Context(),"sftp server exited with error",slog.Error(err))
206+
},
207+
},
188208
}
189209

190210
goa.run(ctx)
191211
}
192212

193213
func (a*agent)handleSSHSession(session ssh.Session)error {
194-
var (
195-
commandstring
196-
args= []string{}
197-
errerror
198-
)
199-
200214
currentUser,err:=user.Current()
201215
iferr!=nil {
202216
returnxerrors.Errorf("get current user: %w",err)
203217
}
204218
username:=currentUser.Username
205219

220+
shell,err:=usershell.Get(username)
221+
iferr!=nil {
222+
returnxerrors.Errorf("get user shell: %w",err)
223+
}
224+
206225
// gliderlabs/ssh returns a command slice of zero
207226
// when a shell is requested.
227+
command:=session.RawCommand()
208228
iflen(session.Command())==0 {
209-
command,err=usershell.Get(username)
210-
iferr!=nil {
211-
returnxerrors.Errorf("get user shell: %w",err)
212-
}
213-
}else {
214-
command=session.Command()[0]
215-
iflen(session.Command())>1 {
216-
args=session.Command()[1:]
217-
}
229+
command=shell
218230
}
219231

220-
signals:=make(chan ssh.Signal)
221-
breaks:=make(chanbool)
222-
deferclose(signals)
223-
deferclose(breaks)
224-
gofunc() {
225-
for {
226-
select {
227-
case<-session.Context().Done():
228-
return
229-
// Ignore signals and breaks for now!
230-
case<-signals:
231-
case<-breaks:
232-
}
233-
}
234-
}()
235-
236-
cmd:=exec.CommandContext(session.Context(),command,args...)
232+
// OpenSSH executes all commands with the users current shell.
233+
// We replicate that behavior for IDE support.
234+
cmd:=exec.CommandContext(session.Context(),shell,"-c",command)
237235
cmd.Env=append(os.Environ(),session.Environ()...)
238236
executablePath,err:=os.Executable()
239237
iferr!=nil {
240238
returnxerrors.Errorf("getting os executable: %w",err)
241239
}
242-
cmd.Env=append(session.Environ(),fmt.Sprintf(`GIT_SSH_COMMAND="%s gitssh --"`,executablePath))
240+
cmd.Env=append(cmd.Env,fmt.Sprintf(`GIT_SSH_COMMAND="%s gitssh --"`,executablePath))
243241

244242
sshPty,windowSize,isPty:=session.Pty()
245243
ifisPty {
@@ -268,7 +266,7 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
268266
}
269267

270268
cmd.Stdout=session
271-
cmd.Stderr=session
269+
cmd.Stderr=session.Stderr()
272270
// This blocks forever until stdin is received if we don't
273271
// use StdinPipe. It's unknown what causes this.
274272
stdinPipe,err:=cmd.StdinPipe()
@@ -282,8 +280,7 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
282280
iferr!=nil {
283281
returnxerrors.Errorf("start: %w",err)
284282
}
285-
_=cmd.Wait()
286-
returnnil
283+
returncmd.Wait()
287284
}
288285

289286
// isClosed returns whether the API is closed or not.

‎agent/agent_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import (
55
"fmt"
66
"io"
77
"net"
8+
"os"
89
"os/exec"
10+
"path/filepath"
911
"runtime"
1012
"strconv"
1113
"strings"
1214
"testing"
1315

1416
"github.com/pion/webrtc/v3"
17+
"github.com/pkg/sftp"
1518
"github.com/stretchr/testify/require"
1619
"go.uber.org/goleak"
1720
"golang.org/x/crypto/ssh"
@@ -94,6 +97,7 @@ func TestAgent(t *testing.T) {
9497

9598
local,err:=net.Listen("tcp","127.0.0.1:0")
9699
require.NoError(t,err)
100+
deferlocal.Close()
97101
tcpAddr,valid=local.Addr().(*net.TCPAddr)
98102
require.True(t,valid)
99103
localPort:=tcpAddr.Port
@@ -113,6 +117,21 @@ func TestAgent(t *testing.T) {
113117
conn.Close()
114118
<-done
115119
})
120+
121+
t.Run("SFTP",func(t*testing.T) {
122+
t.Parallel()
123+
sshClient,err:=setupAgent(t).SSHClient()
124+
require.NoError(t,err)
125+
client,err:=sftp.NewClient(sshClient)
126+
require.NoError(t,err)
127+
tempFile:=filepath.Join(t.TempDir(),"sftp")
128+
file,err:=client.Create(tempFile)
129+
require.NoError(t,err)
130+
err=file.Close()
131+
require.NoError(t,err)
132+
_,err=os.Stat(tempFile)
133+
require.NoError(t,err)
134+
})
116135
}
117136

118137
funcsetupSSHCommand(t*testing.T,beforeArgs []string,afterArgs []string)*exec.Cmd {

‎cli/cliui/resources_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import (
44
"testing"
55
"time"
66

7+
"github.com/stretchr/testify/require"
8+
79
"github.com/coder/coder/cli/cliui"
810
"github.com/coder/coder/coderd/database"
911
"github.com/coder/coder/codersdk"
1012
"github.com/coder/coder/pty/ptytest"
11-
"github.com/stretchr/testify/require"
1213
)
1314

1415
funcTestWorkspaceResources(t*testing.T) {

‎go.mod

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ require (
4848
github.com/fatih/colorv1.13.0
4949
github.com/gliderlabs/sshv0.3.3
5050
github.com/go-chi/chi/v5v5.0.7
51+
github.com/go-chi/httpratev0.5.3
5152
github.com/go-chi/renderv1.0.1
5253
github.com/go-playground/validator/v10v10.10.1
5354
github.com/gohugoio/hugov0.96.0
@@ -60,6 +61,7 @@ require (
6061
github.com/hashicorp/terraform-config-inspectv0.0.0-20211115214459-90acf1ca460f
6162
github.com/hashicorp/terraform-execv0.15.0
6263
github.com/hashicorp/yamuxv0.0.0-20211028200310-0bc27b27de87
64+
github.com/jedib0t/go-pretty/v6v6.3.0
6365
github.com/justinas/nosurfv1.1.1
6466
github.com/kirsle/configdirv0.0.0-20170128060238-e45d2f54772f
6567
github.com/lib/pqv1.10.5
@@ -72,7 +74,9 @@ require (
7274
github.com/pion/transportv0.13.0
7375
github.com/pion/webrtc/v3v3.1.27
7476
github.com/pkg/browserv0.0.0-20210911075715-681adbf594b8
77+
github.com/pkg/sftpv1.13.4
7578
github.com/quasilyte/go-ruleguard/dslv0.3.19
79+
github.com/robfig/cron/v3v3.0.1
7680
github.com/rs/zerologv1.26.1
7781
github.com/spf13/cobrav1.4.0
7882
github.com/spf13/pflagv1.0.5
@@ -83,20 +87,19 @@ require (
8387
go.uber.org/atomicv1.9.0
8488
go.uber.org/goleakv1.1.12
8589
golang.org/x/cryptov0.0.0-20220315160706-3147a52a75dd
90+
golang.org/x/modv0.5.1
8691
golang.org/x/oauth2v0.0.0-20220309155454-6242fa91716a
8792
golang.org/x/syncv0.0.0-20210220032951-036812b2e83c
8893
golang.org/x/sysv0.0.0-20220328115105-d36c6a25d886
94+
golang.org/x/termv0.0.0-20210927222741-03fcf44c2211
8995
golang.org/x/xerrorsv0.0.0-20200804184101-5ec99f83aff1
9096
google.golang.org/apiv0.74.0
9197
google.golang.org/protobufv1.28.0
98+
gopkg.in/DataDog/dd-trace-go.v1v1.37.1
9299
nhooyr.io/websocketv1.8.7
93100
storj.io/drpcv0.0.30
94101
)
95102

96-
requiregithub.com/go-chi/httpratev0.5.3
97-
98-
requiregithub.com/jedib0t/go-pretty/v6v6.3.0
99-
100103
require (
101104
github.com/Azure/go-ansitermv0.0.0-20210617225240-d185dfc1b5a1// indirect
102105
github.com/BurntSushi/tomlv1.0.0// indirect
@@ -171,6 +174,7 @@ require (
171174
github.com/json-iterator/gov1.1.12// indirect
172175
github.com/kballard/go-shellquotev0.0.0-20180428030007-95032a82bc51// indirect
173176
github.com/klauspost/compressv1.15.0// indirect
177+
github.com/kr/fsv0.1.0// indirect
174178
github.com/leodido/go-urnv1.2.1// indirect
175179
github.com/lucas-clemente/quic-gov0.25.1-0.20220307142123-ad1cb27c1b64// indirect
176180
github.com/lucasb-eyer/go-colorfulv1.2.0// indirect
@@ -222,7 +226,6 @@ require (
222226
github.com/prometheus/procfsv0.7.3// indirect
223227
github.com/rivo/tviewv0.0.0-20200712113419-c65badfc3d92// indirect
224228
github.com/rivo/unisegv0.2.0// indirect
225-
github.com/robfig/cron/v3v3.0.1
226229
github.com/russross/blackfriday/v2v2.1.0// indirect
227230
github.com/sirupsen/logrusv1.8.1// indirect
228231
github.com/spf13/aferov1.8.1// indirect
@@ -235,16 +238,13 @@ require (
235238
github.com/zclconf/go-ctyv1.10.0// indirect
236239
github.com/zeebo/errsv1.2.2// indirect
237240
go.opencensus.iov0.23.0// indirect
238-
golang.org/x/modv0.5.1
239241
golang.org/x/netv0.0.0-20220325170049-de3da57026de// indirect
240-
golang.org/x/termv0.0.0-20210927222741-03fcf44c2211
241242
golang.org/x/textv0.3.7// indirect
242243
golang.org/x/timev0.0.0-20211116232009-f0f3c7e86c11// indirect
243244
golang.org/x/toolsv0.1.9// indirect
244245
google.golang.org/appenginev1.6.7// indirect
245246
google.golang.org/genprotov0.0.0-20220324131243-acbaeb5b85eb// indirect
246247
google.golang.org/grpcv1.45.0// indirect
247-
gopkg.in/DataDog/dd-trace-go.v1v1.37.1
248248
gopkg.in/coreos/go-oidc.v2v2.2.1// indirect
249249
gopkg.in/natefinch/lumberjack.v2v2.0.0// indirect
250250
gopkg.in/square/go-jose.v2v2.6.0// indirect

‎go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ github.com/klauspost/crc32 v1.2.0/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3H
11031103
github.com/konsorten/go-windows-terminal-sequencesv1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
11041104
github.com/konsorten/go-windows-terminal-sequencesv1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
11051105
github.com/konsorten/go-windows-terminal-sequencesv1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
1106+
github.com/kr/fsv0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
11061107
github.com/kr/fsv0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
11071108
github.com/kr/logfmtv0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
11081109
github.com/kr/prettyv0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -1438,6 +1439,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
14381439
github.com/pkg/profilev1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
14391440
github.com/pkg/profilev1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
14401441
github.com/pkg/sftpv1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
1442+
github.com/pkg/sftpv1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg=
1443+
github.com/pkg/sftpv1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
14411444
github.com/pmezard/go-difflibv0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14421445
github.com/pmezard/go-difflibv1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
14431446
github.com/pmezard/go-difflibv1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

‎peer/channel.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const (
2121
// For some reason messages larger just don't work...
2222
// This shouldn't be a huge deal for real-world usage.
2323
// See: https://github.com/pion/datachannel/issues/59
24-
maxMessageLength=32*1024//32 KB
24+
maxMessageLength=64*1024//64 KB
2525
)
2626

2727
// newChannel creates a new channel and initializes it.
@@ -145,7 +145,9 @@ func (c *Channel) init() {
145145
ifc.opts.Unordered {
146146
c.reader=c.rwc
147147
}else {
148-
c.reader=bufio.NewReader(c.rwc)
148+
// This must be the max message length otherwise a short
149+
// buffer error can occur.
150+
c.reader=bufio.NewReaderSize(c.rwc,maxMessageLength)
149151
}
150152
close(c.opened)
151153
})

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp