Skip to content

Commit 8bedc8a

Browse files
committed
Merge origin/main
2 parents 854f781 + 31b819e commit 8bedc8a

File tree

107 files changed

+2448
-646
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2448
-646
lines changed

.github/dependabot.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ updates:
5555
- version-update:semver-major
5656

5757
- package-ecosystem: "terraform"
58-
directory: "/examples"
58+
directory: "/examples/templates"
5959
schedule:
6060
interval: "weekly"
6161
time: "06:00"

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
uses: goreleaser/goreleaser-action@v3
8484
with:
8585
version: latest
86-
args: release --rm-dist
86+
args: release --rm-dist --timeout 60m
8787
env:
8888
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8989
AC_USERNAME: ${{ secrets.AC_USERNAME }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ vendor
1414
.eslintcache
1515
yarn-error.log
1616
.idea
17+
.DS_Store
1718

1819
# Front-end ignore
1920
.next/

README.md

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,48 @@ Discord"](https://img.shields.io/badge/join-us%20on%20Discord-gray.svg?longCache
88
Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq)
99
[![codecov](https://codecov.io/gh/coder/coder/branch/main/graph/badge.svg?token=TNLW3OAP6G)](https://codecov.io/gh/coder/coder)
1010

11-
Team-wide CLI for spawning up dev servers on demand, powered by Terraform.
11+
Coder turns your cloud into a fleet of remote development servers.
1212

13-
![Kubernetes workspace in Coder v2](./docs/screenshot.png)
13+
<p align="center">
14+
<img src="./docs/images/hero-image.png">
15+
</p>
1416

15-
## Highlights
17+
**Code more**
1618

17-
Workspaces:
18-
- Code on powerful servers: leverage cloud GPU, GPU, and network speeds
19-
- Use the `coder` CLI: connect via SSH, VS Code, and JetBrains
20-
- Self-serve workspaces: start from team-wide templates (see below)
19+
- Build and test faster
20+
- Leveraging cloud CPUs, RAM, network speeds, etc.
21+
- Access your environment from any place on any client (even an iPad)
22+
- Onboard instantly then stay up to date continuously
2123

22-
Templates:
23-
- Manage the infrastructure behind workspaces with standard Terraform (`.hcl` files)
24-
- Use any OS and architecture: Mac, Windows, Linux, VM, Kubernetes, ARM, etc
25-
- Auto-shutdown or update workspaces when they're not in use!
24+
**Manage less**
2625

26+
- Ensure your entire team is using the same tools and resources
27+
- Rollout critical updates to your developers with one command
28+
- Automatically shut down expensive cloud resources
29+
- Keep your source code and data behind your firewall
30+
31+
## How it works
32+
33+
Coder workspaces are represented with Terraform. But, no Terraform knowledge is
34+
required to get started. We have a database of pre-made templates built into the
35+
product.
36+
37+
<p align="center">
38+
<img src="./docs/images/providers-compute.png">
39+
</p>
40+
41+
Coder workspaces don't stop at compute. You can add storage buckets, secrets, sidecars
42+
and whatever else Terraform lets you dream up.
43+
44+
[Learn more about managing infrastructure.](./docs/templates.md)
45+
46+
## IDE Support
47+
48+
You can use any Web IDE ([code-server](https://github.com/coder/code-server), [projector](https://github.com/JetBrains/projector-server), [Jupyter](https://jupyter.org/), etc.), [JetBrains Gateway](https://www.jetbrains.com/remote-development/gateway/), [VS Code Remote](https://code.visualstudio.com/docs/remote/ssh-tutorial) or even a file sync such as [mutagen](https://mutagen.io/).
49+
50+
<p align="center">
51+
<img src="./docs/images/ide-icons.svg" height=72>
52+
</p>
2753

2854
## Installing Coder
2955

agent/agent.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,25 @@ import (
2121
"time"
2222

2323
"github.com/armon/circbuf"
24+
"github.com/gliderlabs/ssh"
2425
"github.com/google/uuid"
25-
26+
"github.com/pkg/sftp"
2627
"go.uber.org/atomic"
28+
gossh "golang.org/x/crypto/ssh"
29+
"golang.org/x/xerrors"
2730

2831
"cdr.dev/slog"
2932
"github.com/coder/coder/agent/usershell"
3033
"github.com/coder/coder/peer"
3134
"github.com/coder/coder/peerbroker"
3235
"github.com/coder/coder/pty"
3336
"github.com/coder/retry"
37+
)
3438

35-
"github.com/pkg/sftp"
36-
37-
"github.com/gliderlabs/ssh"
38-
gossh "golang.org/x/crypto/ssh"
39-
"golang.org/x/xerrors"
39+
const (
40+
ProtocolReconnectingPTY = "reconnecting-pty"
41+
ProtocolSSH = "ssh"
42+
ProtocolDial = "dial"
4043
)
4144

4245
type Options struct {
@@ -174,17 +177,25 @@ func (*agent) runStartupScript(ctx context.Context, script string) error {
174177
defer func() {
175178
_ = writer.Close()
176179
}()
180+
177181
caller := "-c"
178182
if runtime.GOOS == "windows" {
179183
caller = "/c"
180184
}
185+
181186
cmd := exec.CommandContext(ctx, shell, caller, script)
182187
cmd.Stdout = writer
183188
cmd.Stderr = writer
184189
err = cmd.Run()
185190
if err != nil {
191+
// cmd.Run does not return a context canceled error, it returns "signal: killed".
192+
if ctx.Err() != nil {
193+
return ctx.Err()
194+
}
195+
186196
return xerrors.Errorf("run: %w", err)
187197
}
198+
188199
return nil
189200
}
190201

@@ -208,11 +219,11 @@ func (a *agent) handlePeerConn(ctx context.Context, conn *peer.Conn) {
208219
}
209220

210221
switch channel.Protocol() {
211-
case "ssh":
222+
case ProtocolSSH:
212223
go a.sshServer.HandleConn(channel.NetConn())
213-
case "reconnecting-pty":
224+
case ProtocolReconnectingPTY:
214225
go a.handleReconnectingPTY(ctx, channel.Label(), channel.NetConn())
215-
case "dial":
226+
case ProtocolDial:
216227
go a.handleDial(ctx, channel.Label(), channel.NetConn())
217228
default:
218229
a.logger.Warn(ctx, "unhandled protocol from channel",
@@ -380,6 +391,16 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
380391
return err
381392
}
382393

394+
if ssh.AgentRequested(session) {
395+
l, err := ssh.NewAgentListener()
396+
if err != nil {
397+
return xerrors.Errorf("new agent listener: %w", err)
398+
}
399+
defer l.Close()
400+
go ssh.ForwardAgentConnections(l, session)
401+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "SSH_AUTH_SOCK", l.Addr().String()))
402+
}
403+
383404
sshPty, windowSize, isPty := session.Pty()
384405
if isPty {
385406
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", sshPty.Term))
@@ -478,8 +499,8 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, rawID string, conn ne
478499
a.logger.Warn(ctx, "start reconnecting pty command", slog.F("id", id))
479500
}
480501

481-
// Default to buffer 64KB.
482-
circularBuffer, err := circbuf.NewBuffer(64 * 1024)
502+
// Default to buffer 64KiB.
503+
circularBuffer, err := circbuf.NewBuffer(64 << 10)
483504
if err != nil {
484505
a.logger.Warn(ctx, "create circular buffer", slog.Error(err))
485506
return

agent/agent_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ func TestAgent(t *testing.T) {
172172
tempPath := filepath.Join(os.TempDir(), "content.txt")
173173
content := "somethingnice"
174174
setupAgent(t, agent.Metadata{
175-
StartupScript: "echo " + content + " > " + tempPath,
175+
StartupScript: fmt.Sprintf("echo %s > %s", content, tempPath),
176176
}, 0)
177+
177178
var gotContent string
178179
require.Eventually(t, func() bool {
179180
content, err := os.ReadFile(tempPath)
@@ -202,6 +203,7 @@ func TestAgent(t *testing.T) {
202203
// it seems like it could be either.
203204
t.Skip("ConPTY appears to be inconsistent on Windows.")
204205
}
206+
205207
conn := setupAgent(t, agent.Metadata{}, 0)
206208
id := uuid.NewString()
207209
netConn, err := conn.ReconnectingPTY(id, 100, 100)
@@ -228,6 +230,7 @@ func TestAgent(t *testing.T) {
228230
}
229231
}
230232
}
233+
231234
matchEchoCommand := func(line string) bool {
232235
return strings.Contains(line, "echo test")
233236
}

agent/conn.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type Conn struct {
3636
// be reconnected to via ID.
3737
func (c *Conn) ReconnectingPTY(id string, height, width uint16) (net.Conn, error) {
3838
channel, err := c.CreateChannel(context.Background(), fmt.Sprintf("%s:%d:%d", id, height, width), &peer.ChannelOptions{
39-
Protocol: "reconnecting-pty",
39+
Protocol: ProtocolReconnectingPTY,
4040
})
4141
if err != nil {
4242
return nil, xerrors.Errorf("pty: %w", err)
@@ -47,7 +47,7 @@ func (c *Conn) ReconnectingPTY(id string, height, width uint16) (net.Conn, error
4747
// SSH dials the built-in SSH server.
4848
func (c *Conn) SSH() (net.Conn, error) {
4949
channel, err := c.CreateChannel(context.Background(), "ssh", &peer.ChannelOptions{
50-
Protocol: "ssh",
50+
Protocol: ProtocolSSH,
5151
})
5252
if err != nil {
5353
return nil, xerrors.Errorf("dial: %w", err)
@@ -87,7 +87,7 @@ func (c *Conn) DialContext(ctx context.Context, network string, addr string) (ne
8787
}
8888

8989
channel, err := c.CreateChannel(ctx, u.String(), &peer.ChannelOptions{
90-
Protocol: "dial",
90+
Protocol: ProtocolDial,
9191
Unordered: strings.HasPrefix(network, "udp"),
9292
})
9393
if err != nil {

cli/config/file.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ func (r Root) Organization() File {
2121
return File(filepath.Join(string(r), "organization"))
2222
}
2323

24+
func (r Root) DotfilesURL() File {
25+
return File(filepath.Join(string(r), "dotfilesurl"))
26+
}
27+
2428
// File provides convenience methods for interacting with *os.File.
2529
type File string
2630

cli/configssh.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ func configSSH() *cobra.Command {
3838
Annotations: workspaceCommand,
3939
Use: "config-ssh",
4040
Short: "Populate your SSH config with Host entries for all of your workspaces",
41+
Example: `
42+
- You can use -o (or --ssh-option) so set SSH options to be used for all your
43+
workspaces.
44+
45+
` + cliui.Styles.Code.Render("$ coder config-ssh -o ForwardAgent=yes"),
4146
RunE: func(cmd *cobra.Command, args []string) error {
4247
client, err := createClient(cmd)
4348
if err != nil {

0 commit comments

Comments
 (0)