feat: use agent v2 API to fetch manifest (#11832)

Agent uses the v2 API to obtain the manifest, instead of the HTTP API.
This commit is contained in:
Spike Curtis
2024-01-30 10:11:28 +04:00
committed by GitHub
parent 9cf4e7f15a
commit da8bb1c198
8 changed files with 91 additions and 83 deletions
+5 -26
View File
@@ -135,35 +135,13 @@ type Script struct {
Script string `json:"script"`
}
// Manifest fetches manifest for the currently authenticated workspace agent.
func (c *Client) Manifest(ctx context.Context) (Manifest, error) {
res, err := c.SDK.Request(ctx, http.MethodGet, "/api/v2/workspaceagents/me/manifest", nil)
if err != nil {
return Manifest{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return Manifest{}, codersdk.ReadBodyAsError(res)
}
var agentMeta Manifest
err = json.NewDecoder(res.Body).Decode(&agentMeta)
if err != nil {
return Manifest{}, err
}
err = c.rewriteDerpMap(agentMeta.DERPMap)
if err != nil {
return Manifest{}, err
}
return agentMeta, nil
}
// rewriteDerpMap rewrites the DERP map to use the access URL of the SDK as the
// RewriteDERPMap rewrites the DERP map to use the access URL of the SDK as the
// "embedded relay" access URL. The passed derp map is modified in place.
//
// Agents can provide an arbitrary access URL that may be different that the
// globally configured one. This breaks the built-in DERP, which would continue
// to reference the global access URL.
func (c *Client) rewriteDerpMap(derpMap *tailcfg.DERPMap) error {
func (c *Client) RewriteDERPMap(derpMap *tailcfg.DERPMap) {
accessingPort := c.SDK.URL.Port()
if accessingPort == "" {
accessingPort = "80"
@@ -173,7 +151,9 @@ func (c *Client) rewriteDerpMap(derpMap *tailcfg.DERPMap) error {
}
accessPort, err := strconv.Atoi(accessingPort)
if err != nil {
return xerrors.Errorf("convert accessing port %q: %w", accessingPort, err)
// this should never happen because URL.Port() returns the empty string if the port is not
// valid.
c.SDK.Logger().Critical(context.Background(), "failed to parse URL port", slog.F("port", accessingPort))
}
for _, region := range derpMap.Regions {
if !region.EmbeddedRelay {
@@ -189,7 +169,6 @@ func (c *Client) rewriteDerpMap(derpMap *tailcfg.DERPMap) error {
node.ForceHTTP = c.SDK.URL.Scheme == "http"
}
}
return nil
}
// Listen connects to the workspace agent API WebSocket
+19 -25
View File
@@ -5,7 +5,6 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"sync/atomic"
"testing"
"time"
@@ -20,37 +19,32 @@ import (
"github.com/coder/coder/v2/testutil"
)
func TestWorkspaceAgentMetadata(t *testing.T) {
func TestWorkspaceRewriteDERPMap(t *testing.T) {
t.Parallel()
// This test ensures that the DERP map returned properly
// mutates built-in DERPs with the client access URL.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
httpapi.Write(context.Background(), w, http.StatusOK, agentsdk.Manifest{
DERPMap: &tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
EmbeddedRelay: true,
RegionID: 1,
Nodes: []*tailcfg.DERPNode{{
HostName: "bananas.org",
DERPPort: 1,
}},
},
},
// This test ensures that RewriteDERPMap mutates built-in DERPs with the
// client access URL.
dm := &tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
EmbeddedRelay: true,
RegionID: 1,
Nodes: []*tailcfg.DERPNode{{
HostName: "bananas.org",
DERPPort: 1,
}},
},
})
}))
parsed, err := url.Parse(srv.URL)
},
}
parsed, err := url.Parse("https://coconuts.org:44558")
require.NoError(t, err)
client := agentsdk.New(parsed)
manifest, err := client.Manifest(context.Background())
require.NoError(t, err)
region := manifest.DERPMap.Regions[1]
client.RewriteDERPMap(dm)
region := dm.Regions[1]
require.True(t, region.EmbeddedRelay)
require.Len(t, region.Nodes, 1)
node := region.Nodes[0]
require.Equal(t, parsed.Hostname(), node.HostName)
require.Equal(t, parsed.Port(), strconv.Itoa(node.DERPPort))
require.Equal(t, "coconuts.org", node.HostName)
require.Equal(t, 44558, node.DERPPort)
}
func TestAgentReportStats(t *testing.T) {