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

Commitf0f90fc

Browse files
committed
maybe?
2 parentsae46996 +114ba45 commitf0f90fc

File tree

10 files changed

+1820
-1756
lines changed

10 files changed

+1820
-1756
lines changed

‎agent/agent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,7 @@ func (a *agent) createTailnet(
14081408
ifrPTYServeErr!=nil&&
14091409
a.gracefulCtx.Err()==nil&&
14101410
!strings.Contains(rPTYServeErr.Error(),"use of closed network connection") {
1411-
a.logger.Error(ctx,"error serving reconnecting PTY",slog.Error(err))
1411+
a.logger.Error(ctx,"error serving reconnecting PTY",slog.Error(rPTYServeErr))
14121412
}
14131413
});err!=nil {
14141414
returnnil,err

‎cli/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,15 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
620620
returnxerrors.Errorf("parse ssh config options %q: %w",vals.SSHConfig.SSHConfigOptions.String(),err)
621621
}
622622

623+
// The workspace hostname suffix is always interpreted as implicitly beginning with a single dot, so it is
624+
// a config error to explicitly include the dot. This ensures that we always interpret the suffix as a
625+
// separate DNS label, and not just an ordinary string suffix. E.g. a suffix of 'coder' will match
626+
// 'en.coder' but not 'encoder'.
627+
ifstrings.HasPrefix(vals.WorkspaceHostnameSuffix.String(),".") {
628+
returnxerrors.Errorf("you must omit any leading . in workspace hostname suffix: %s",
629+
vals.WorkspaceHostnameSuffix.String())
630+
}
631+
623632
options:=&coderd.Options{
624633
AccessURL:vals.AccessURL.Value(),
625634
AppHostname:appHostname,

‎cli/ssh.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func (r *RootCmd) ssh() *serpent.Command {
6565
var (
6666
stdiobool
6767
hostPrefixstring
68+
hostnameSuffixstring
6869
forwardAgentbool
6970
forwardGPGbool
7071
identityAgentstring
@@ -202,10 +203,14 @@ func (r *RootCmd) ssh() *serpent.Command {
202203
parsedEnv=append(parsedEnv, [2]string{k,v})
203204
}
204205

205-
workspaceInput:=strings.TrimPrefix(inv.Args[0],hostPrefix)
206-
// convert workspace name format into owner/workspace.agent
207-
namedWorkspace:=normalizeWorkspaceInput(workspaceInput)
208-
workspace,workspaceAgent,err:=getWorkspaceAndAgent(ctx,inv,client,!disableAutostart,namedWorkspace)
206+
deploymentSSHConfig:= codersdk.SSHConfigResponse{
207+
HostnamePrefix:hostPrefix,
208+
HostnameSuffix:hostnameSuffix,
209+
}
210+
211+
workspace,workspaceAgent,err:=findWorkspaceAndAgentByHostname(
212+
ctx,inv,client,
213+
inv.Args[0],deploymentSSHConfig,disableAutostart)
209214
iferr!=nil {
210215
returnerr
211216
}
@@ -564,6 +569,12 @@ func (r *RootCmd) ssh() *serpent.Command {
564569
Description:"Strip this prefix from the provided hostname to determine the workspace name. This is useful when used as part of an OpenSSH proxy command.",
565570
Value:serpent.StringOf(&hostPrefix),
566571
},
572+
{
573+
Flag:"hostname-suffix",
574+
Env:"CODER_SSH_HOSTNAME_SUFFIX",
575+
Description:"Strip this suffix from the provided hostname to determine the workspace name. This is useful when used as part of an OpenSSH proxy command. The suffix must be specified without a leading . character.",
576+
Value:serpent.StringOf(&hostnameSuffix),
577+
},
567578
{
568579
Flag:"forward-agent",
569580
FlagShorthand:"A",
@@ -656,6 +667,30 @@ func (r *RootCmd) ssh() *serpent.Command {
656667
returncmd
657668
}
658669

670+
// findWorkspaceAndAgentByHostname parses the hostname from the commandline and finds the workspace and agent it
671+
// corresponds to, taking into account any name prefixes or suffixes configured (e.g. myworkspace.coder, or
672+
// vscode-coder--myusername--myworkspace).
673+
funcfindWorkspaceAndAgentByHostname(
674+
ctx context.Context,inv*serpent.Invocation,client*codersdk.Client,
675+
hostnamestring,config codersdk.SSHConfigResponse,disableAutostartbool,
676+
) (
677+
codersdk.Workspace, codersdk.WorkspaceAgent,error,
678+
) {
679+
// for suffixes, we don't explicitly get the . and must add it. This is to ensure that the suffix is always
680+
// interpreted as a dotted label in DNS names, not just any string suffix. That is, a suffix of 'coder' will
681+
// match a hostname like 'en.coder', but not 'encoder'.
682+
qualifiedSuffix:="."+config.HostnameSuffix
683+
684+
switch {
685+
caseconfig.HostnamePrefix!=""&&strings.HasPrefix(hostname,config.HostnamePrefix):
686+
hostname=strings.TrimPrefix(hostname,config.HostnamePrefix)
687+
caseconfig.HostnameSuffix!=""&&strings.HasSuffix(hostname,qualifiedSuffix):
688+
hostname=strings.TrimSuffix(hostname,qualifiedSuffix)
689+
}
690+
hostname=normalizeWorkspaceInput(hostname)
691+
returngetWorkspaceAndAgent(ctx,inv,client,!disableAutostart,hostname)
692+
}
693+
659694
// watchAndClose ensures closer is called if the context is canceled or
660695
// the workspace reaches the stopped state.
661696
//

‎cli/ssh_test.go

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,67 +1690,85 @@ func TestSSH(t *testing.T) {
16901690
}
16911691
})
16921692

1693-
t.Run("SSHHostPrefix",func(t*testing.T) {
1693+
t.Run("SSHHost",func(t*testing.T) {
16941694
t.Parallel()
1695-
client,workspace,agentToken:=setupWorkspaceForAgent(t)
1696-
_,_=tGoContext(t,func(ctx context.Context) {
1697-
// Run this async so the SSH command has to wait for
1698-
// the build and agent to connect!
1699-
_=agenttest.New(t,client.URL,agentToken)
1700-
<-ctx.Done()
1701-
})
17021695

1703-
clientOutput,clientInput:=io.Pipe()
1704-
serverOutput,serverInput:=io.Pipe()
1705-
deferfunc() {
1706-
for_,c:=range []io.Closer{clientOutput,clientInput,serverOutput,serverInput} {
1707-
_=c.Close()
1708-
}
1709-
}()
1696+
testCases:= []struct {
1697+
name,hostnameFormatstring
1698+
flags []string
1699+
}{
1700+
{"Prefix","coder.dummy.com--%s--%s", []string{"--ssh-host-prefix","coder.dummy.com--"}},
1701+
{"Suffix","%s--%s.coder", []string{"--hostname-suffix","coder"}},
1702+
{"Both","%s--%s.coder", []string{"--hostname-suffix","coder","--ssh-host-prefix","coder.dummy.com--"}},
1703+
}
1704+
for_,tc:=rangetestCases {
1705+
t.Run(tc.name,func(t*testing.T) {
1706+
t.Parallel()
17101707

1711-
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
1712-
defercancel()
1708+
client,workspace,agentToken:=setupWorkspaceForAgent(t)
1709+
_,_=tGoContext(t,func(ctx context.Context) {
1710+
// Run this async so the SSH command has to wait for
1711+
// the build and agent to connect!
1712+
_=agenttest.New(t,client.URL,agentToken)
1713+
<-ctx.Done()
1714+
})
17131715

1714-
user,err:=client.User(ctx,codersdk.Me)
1715-
require.NoError(t,err)
1716+
clientOutput,clientInput:=io.Pipe()
1717+
serverOutput,serverInput:=io.Pipe()
1718+
deferfunc() {
1719+
for_,c:=range []io.Closer{clientOutput,clientInput,serverOutput,serverInput} {
1720+
_=c.Close()
1721+
}
1722+
}()
17161723

1717-
inv,root:=clitest.New(t,"ssh","--stdio","--ssh-host-prefix","coder.dummy.com--",fmt.Sprintf("coder.dummy.com--%s--%s",user.Username,workspace.Name))
1718-
clitest.SetupConfig(t,client,root)
1719-
inv.Stdin=clientOutput
1720-
inv.Stdout=serverInput
1721-
inv.Stderr=io.Discard
1724+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
1725+
defercancel()
17221726

1723-
cmdDone:=tGo(t,func() {
1724-
err:=inv.WithContext(ctx).Run()
1725-
assert.NoError(t,err)
1726-
})
1727+
user,err:=client.User(ctx,codersdk.Me)
1728+
require.NoError(t,err)
17271729

1728-
conn,channels,requests,err:=ssh.NewClientConn(&stdioConn{
1729-
Reader:serverOutput,
1730-
Writer:clientInput,
1731-
},"",&ssh.ClientConfig{
1732-
// #nosec
1733-
HostKeyCallback:ssh.InsecureIgnoreHostKey(),
1734-
})
1735-
require.NoError(t,err)
1736-
deferconn.Close()
1730+
args:= []string{"ssh","--stdio"}
1731+
args=append(args,tc.flags...)
1732+
args=append(args,fmt.Sprintf(tc.hostnameFormat,user.Username,workspace.Name))
1733+
inv,root:=clitest.New(t,args...)
1734+
clitest.SetupConfig(t,client,root)
1735+
inv.Stdin=clientOutput
1736+
inv.Stdout=serverInput
1737+
inv.Stderr=io.Discard
17371738

1738-
sshClient:=ssh.NewClient(conn,channels,requests)
1739-
session,err:=sshClient.NewSession()
1740-
require.NoError(t,err)
1741-
defersession.Close()
1739+
cmdDone:=tGo(t,func() {
1740+
err:=inv.WithContext(ctx).Run()
1741+
assert.NoError(t,err)
1742+
})
17421743

1743-
command:="sh -c exit"
1744-
ifruntime.GOOS=="windows" {
1745-
command="cmd.exe /c exit"
1746-
}
1747-
err=session.Run(command)
1748-
require.NoError(t,err)
1749-
err=sshClient.Close()
1750-
require.NoError(t,err)
1751-
_=clientOutput.Close()
1744+
conn,channels,requests,err:=ssh.NewClientConn(&stdioConn{
1745+
Reader:serverOutput,
1746+
Writer:clientInput,
1747+
},"",&ssh.ClientConfig{
1748+
// #nosec
1749+
HostKeyCallback:ssh.InsecureIgnoreHostKey(),
1750+
})
1751+
require.NoError(t,err)
1752+
deferconn.Close()
17521753

1753-
<-cmdDone
1754+
sshClient:=ssh.NewClient(conn,channels,requests)
1755+
session,err:=sshClient.NewSession()
1756+
require.NoError(t,err)
1757+
defersession.Close()
1758+
1759+
command:="sh -c exit"
1760+
ifruntime.GOOS=="windows" {
1761+
command="cmd.exe /c exit"
1762+
}
1763+
err=session.Run(command)
1764+
require.NoError(t,err)
1765+
err=sshClient.Close()
1766+
require.NoError(t,err)
1767+
_=clientOutput.Close()
1768+
1769+
<-cmdDone
1770+
})
1771+
}
17541772
})
17551773
}
17561774

‎cli/testdata/coder_ssh_--help.golden

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ OPTIONS:
2323
locally and will not be started for you. If a GPG agent is already
2424
running in the workspace, it will be attempted to be killed.
2525

26+
--hostname-suffix string, $CODER_SSH_HOSTNAME_SUFFIX
27+
Strip this suffix from the provided hostname to determine the
28+
workspace name. This is useful when used as part of an OpenSSH proxy
29+
command. The suffix must be specified without a leading . character.
30+
2631
--identity-agent string, $CODER_SSH_IDENTITY_AGENT
2732
Specifies which identity agent to use (overrides $SSH_AUTH_SOCK),
2833
forward agent must also be enabled.

‎docs/admin/templates/extending-templates/index.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,55 @@ and can be hidden directly in the
8787
resource. You can arrange the display orientation of Coder apps in your template
8888
using[resource ordering](./resource-ordering.md).
8989

90+
###Coder app examples
91+
92+
<divclass="tabs">
93+
94+
You can use these examples to add new Coder apps:
95+
96+
##code-server
97+
98+
```hcl
99+
resource "coder_app" "code-server" {
100+
agent_id = coder_agent.main.id
101+
slug = "code-server"
102+
display_name = "code-server"
103+
url = "http://localhost:13337/?folder=/home/${local.username}"
104+
icon = "/icon/code.svg"
105+
subdomain = false
106+
share = "owner"
107+
}
108+
```
109+
110+
##Filebrowser
111+
112+
```hcl
113+
resource "coder_app" "filebrowser" {
114+
agent_id = coder_agent.main.id
115+
display_name = "file browser"
116+
slug = "filebrowser"
117+
url = "http://localhost:13339"
118+
icon = "/icon/database.svg"
119+
subdomain = true
120+
share = "owner"
121+
}
122+
```
123+
124+
##Zed
125+
126+
```hcl
127+
resource "coder_app" "zed" {
128+
agent_id = coder_agent.main.id
129+
slug = "slug"
130+
display_name = "Zed"
131+
external = true
132+
url = "zed://ssh/coder.${data.coder_workspace.me.name}"
133+
icon = "/icon/zed.svg"
134+
}
135+
```
136+
137+
</div>
138+
90139
Check out our[module registry](https://registry.coder.com/modules) for
91140
additional Coder apps from the team and our OSS community.
92141

‎docs/images/icons/inbox-in.svg

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp