mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
* Add client for agent * Cleanup code * Fix linting error * Rename routes to be simpler * Rename workspace history to workspace build * Refactor HTTP middlewares to use UUIDs * Cleanup routes * Compiles! * Fix files and organizations * Fix querying * Fix agent lock * Cleanup database abstraction * Add parameters * Fix linting errors * Fix log race * Lock on close wait * Fix log cleanup * Fix e2e tests * Fix upstream version of opencensus-go * Update coderdtest.go * Fix coverpkg * Fix codecov ignore
111 lines
3.3 KiB
Go
111 lines
3.3 KiB
Go
package codersdk
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/hashicorp/yamux"
|
|
"golang.org/x/xerrors"
|
|
"nhooyr.io/websocket"
|
|
|
|
"github.com/coder/coder/coderd"
|
|
"github.com/coder/coder/httpmw"
|
|
"github.com/coder/coder/peer"
|
|
"github.com/coder/coder/peerbroker"
|
|
"github.com/coder/coder/peerbroker/proto"
|
|
"github.com/coder/coder/provisionersdk"
|
|
)
|
|
|
|
func (c *Client) WorkspaceResource(ctx context.Context, id uuid.UUID) (coderd.WorkspaceResource, error) {
|
|
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceresources/%s", id), nil)
|
|
if err != nil {
|
|
return coderd.WorkspaceResource{}, err
|
|
}
|
|
defer res.Body.Close()
|
|
if res.StatusCode != http.StatusOK {
|
|
return coderd.WorkspaceResource{}, readBodyAsError(res)
|
|
}
|
|
var resource coderd.WorkspaceResource
|
|
return resource, json.NewDecoder(res.Body).Decode(&resource)
|
|
}
|
|
|
|
// DialWorkspaceAgent creates a connection to the specified resource.
|
|
func (c *Client) DialWorkspaceAgent(ctx context.Context, resource uuid.UUID) (proto.DRPCPeerBrokerClient, error) {
|
|
serverURL, err := c.URL.Parse(fmt.Sprintf("/api/v2/workspaceresources/%s/dial", resource.String()))
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("parse url: %w", err)
|
|
}
|
|
jar, err := cookiejar.New(nil)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("create cookie jar: %w", err)
|
|
}
|
|
jar.SetCookies(serverURL, []*http.Cookie{{
|
|
Name: httpmw.AuthCookie,
|
|
Value: c.SessionToken,
|
|
}})
|
|
httpClient := &http.Client{
|
|
Jar: jar,
|
|
}
|
|
conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{
|
|
HTTPClient: httpClient,
|
|
// Need to disable compression to avoid a data-race.
|
|
CompressionMode: websocket.CompressionDisabled,
|
|
})
|
|
if err != nil {
|
|
if res == nil {
|
|
return nil, err
|
|
}
|
|
return nil, readBodyAsError(res)
|
|
}
|
|
config := yamux.DefaultConfig()
|
|
config.LogOutput = io.Discard
|
|
session, err := yamux.Client(websocket.NetConn(ctx, conn, websocket.MessageBinary), config)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("multiplex client: %w", err)
|
|
}
|
|
return proto.NewDRPCPeerBrokerClient(provisionersdk.Conn(session)), nil
|
|
}
|
|
|
|
// ListenWorkspaceAgent connects as a workspace agent.
|
|
// It obtains the agent ID based off the session token.
|
|
func (c *Client) ListenWorkspaceAgent(ctx context.Context, opts *peer.ConnOptions) (*peerbroker.Listener, error) {
|
|
serverURL, err := c.URL.Parse("/api/v2/workspaceresources/agent")
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("parse url: %w", err)
|
|
}
|
|
jar, err := cookiejar.New(nil)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("create cookie jar: %w", err)
|
|
}
|
|
jar.SetCookies(serverURL, []*http.Cookie{{
|
|
Name: httpmw.AuthCookie,
|
|
Value: c.SessionToken,
|
|
}})
|
|
httpClient := &http.Client{
|
|
Jar: jar,
|
|
}
|
|
conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{
|
|
HTTPClient: httpClient,
|
|
// Need to disable compression to avoid a data-race.
|
|
CompressionMode: websocket.CompressionDisabled,
|
|
})
|
|
if err != nil {
|
|
if res == nil {
|
|
return nil, err
|
|
}
|
|
return nil, readBodyAsError(res)
|
|
}
|
|
config := yamux.DefaultConfig()
|
|
config.LogOutput = io.Discard
|
|
session, err := yamux.Client(websocket.NetConn(ctx, conn, websocket.MessageBinary), config)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("multiplex client: %w", err)
|
|
}
|
|
return peerbroker.Listen(session, nil, opts)
|
|
}
|