mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: Add templates to create working release (#422)
* Add templates
* Move API structs to codersdk
* Back to green tests!
* It all works, but now with tea! 🧋
* It works!
* Add cancellation to provisionerd
* Tests pass!
* Add deletion of workspaces and projects
* Fix agent lock
* Add clog
* Fix linting errors
* Remove unused CLI tests
* Rename daemon to start
* Fix leaking command
* Fix promptui test
* Update agent connection frequency
* Skip login tests on Windows
* Increase tunnel connect timeout
* Fix templater
* Lower test requirements
* Fix embed
* Disable promptui tests for Windows
* Fix write newline
* Fix PTY write newline
* Fix CloseReader
* Fix compilation on Windows
* Fix linting error
* Remove bubbletea
* Cleanup readwriter
* Use embedded templates instead of serving over API
* Move templates to examples
* Improve workspace create flow
* Fix Windows build
* Fix tests
* Fix linting errors
* Fix untar with extracting max size
* Fix newline char
This commit is contained in:
+72
-71
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"sync"
|
||||
@@ -85,6 +86,76 @@ type server struct {
|
||||
sshServer *ssh.Server
|
||||
}
|
||||
|
||||
func (s *server) run(ctx context.Context) {
|
||||
var peerListener *peerbroker.Listener
|
||||
var err error
|
||||
// An exponential back-off occurs when the connection is failing to dial.
|
||||
// This is to prevent server spam in case of a coderd outage.
|
||||
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
|
||||
peerListener, err = s.clientDialer(ctx, s.options)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Warn(context.Background(), "failed to dial", slog.Error(err))
|
||||
continue
|
||||
}
|
||||
s.options.Logger.Debug(context.Background(), "connected")
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := peerListener.Accept()
|
||||
if err != nil {
|
||||
if s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Debug(ctx, "peer listener accept exited; restarting connection", slog.Error(err))
|
||||
s.run(ctx)
|
||||
return
|
||||
}
|
||||
s.closeMutex.Lock()
|
||||
s.connCloseWait.Add(1)
|
||||
s.closeMutex.Unlock()
|
||||
go s.handlePeerConn(ctx, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
|
||||
go func() {
|
||||
<-conn.Closed()
|
||||
s.connCloseWait.Done()
|
||||
}()
|
||||
for {
|
||||
channel, err := conn.Accept(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, peer.ErrClosed) || s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Debug(ctx, "accept channel from peer connection", slog.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
switch channel.Protocol() {
|
||||
case "ssh":
|
||||
s.sshServer.HandleConn(channel.NetConn())
|
||||
default:
|
||||
s.options.Logger.Warn(ctx, "unhandled protocol from channel",
|
||||
slog.F("protocol", channel.Protocol()),
|
||||
slog.F("label", channel.Label()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) init(ctx context.Context) {
|
||||
// Clients' should ignore the host key when connecting.
|
||||
// The agent needs to authenticate with coderd to SSH,
|
||||
@@ -197,7 +268,7 @@ func (*server) handleSSHSession(session ssh.Session) error {
|
||||
}()
|
||||
|
||||
cmd := exec.CommandContext(session.Context(), command, args...)
|
||||
cmd.Env = session.Environ()
|
||||
cmd.Env = append(os.Environ(), session.Environ()...)
|
||||
|
||||
sshPty, windowSize, isPty := session.Pty()
|
||||
if isPty {
|
||||
@@ -244,76 +315,6 @@ func (*server) handleSSHSession(session ssh.Session) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) run(ctx context.Context) {
|
||||
var peerListener *peerbroker.Listener
|
||||
var err error
|
||||
// An exponential back-off occurs when the connection is failing to dial.
|
||||
// This is to prevent server spam in case of a coderd outage.
|
||||
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
|
||||
peerListener, err = s.clientDialer(ctx, s.options)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Warn(context.Background(), "failed to dial", slog.Error(err))
|
||||
continue
|
||||
}
|
||||
s.options.Logger.Debug(context.Background(), "connected")
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := peerListener.Accept()
|
||||
if err != nil {
|
||||
if s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Debug(ctx, "peer listener accept exited; restarting connection", slog.Error(err))
|
||||
s.run(ctx)
|
||||
return
|
||||
}
|
||||
s.closeMutex.Lock()
|
||||
s.connCloseWait.Add(1)
|
||||
s.closeMutex.Unlock()
|
||||
go s.handlePeerConn(ctx, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
|
||||
go func() {
|
||||
<-conn.Closed()
|
||||
s.connCloseWait.Done()
|
||||
}()
|
||||
for {
|
||||
channel, err := conn.Accept(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, peer.ErrClosed) || s.isClosed() {
|
||||
return
|
||||
}
|
||||
s.options.Logger.Debug(ctx, "accept channel from peer connection", slog.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
switch channel.Protocol() {
|
||||
case "ssh":
|
||||
s.sshServer.HandleConn(channel.NetConn())
|
||||
default:
|
||||
s.options.Logger.Warn(ctx, "unhandled protocol from channel",
|
||||
slog.F("protocol", channel.Protocol()),
|
||||
slog.F("label", channel.Label()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isClosed returns whether the API is closed or not.
|
||||
func (s *server) isClosed() bool {
|
||||
select {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package usershell
|
||||
|
||||
import "os/exec"
|
||||
|
||||
// Get returns the command prompt binary name.
|
||||
func Get(username string) (string, error) {
|
||||
_, err := exec.LookPath("powershell.exe")
|
||||
if err == nil {
|
||||
return "powershell.exe", nil
|
||||
}
|
||||
return "cmd.exe", nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user