From 6e83a5026c01cbec33efd37b6d1fc63848bcbfa6 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 18:55:19 +0000 Subject: [PATCH 1/8] chore: remove resources calls --- cli/agent_test.go | 11 +- cli/portforward_test.go | 12 +- cli/show.go | 6 +- cli/speedtest_test.go | 2 +- cli/ssh.go | 5 +- coderd/activitybump_test.go | 4 +- coderd/coderd.go | 8 - coderd/coderdtest/authorize.go | 16 +- coderd/coderdtest/coderdtest.go | 8 +- coderd/workspaceagents_test.go | 6 +- coderd/workspacebuilds_test.go | 12 +- coderd/workspaceresources.go | 98 -------- coderd/workspaceresources_test.go | 212 ------------------ coderd/workspaces_test.go | 186 +++++++++++++++ codersdk/workspaceagents.go | 55 +++++ codersdk/workspacebuilds.go | 33 +-- codersdk/workspaceresources.go | 98 -------- site/src/api/api.ts | 9 - .../xServices/terminal/terminalXService.ts | 4 +- 19 files changed, 297 insertions(+), 488 deletions(-) delete mode 100644 coderd/workspaceresources.go delete mode 100644 coderd/workspaceresources_test.go delete mode 100644 codersdk/workspaceresources.go diff --git a/cli/agent_test.go b/cli/agent_test.go index 6dd8849b74d79..0bd65c63a62e4 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -61,9 +61,10 @@ func TestWorkspaceAgent(t *testing.T) { errC <- cmd.ExecuteContext(ctx) }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) - if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) { + resources := workspace.LatestBuild.Resources + if assert.NotEmpty(t, workspace.LatestBuild.Resources) && assert.NotEmpty(t, resources[0].Agents) { assert.NotEmpty(t, resources[0].Agents[0].Version) } dialer, err := client.DialWorkspaceAgentTailnet(ctx, slog.Logger{}, resources[0].Agents[0].ID) @@ -121,8 +122,9 @@ func TestWorkspaceAgent(t *testing.T) { errC <- cmd.ExecuteContext(ctx) }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) + resources := workspace.LatestBuild.Resources if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) { assert.NotEmpty(t, resources[0].Agents[0].Version) } @@ -181,8 +183,9 @@ func TestWorkspaceAgent(t *testing.T) { errC <- cmd.ExecuteContext(ctx) }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) + resources := workspace.LatestBuild.Resources if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) { assert.NotEmpty(t, resources[0].Agents[0].Version) } diff --git a/cli/portforward_test.go b/cli/portforward_test.go index 62385b999a5fb..7f98ee38135c9 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -114,9 +114,9 @@ func TestPortForward(t *testing.T) { // Setup agent once to be shared between test-cases (avoid expensive // non-parallel setup). var ( - client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user = coderdtest.CreateFirstUser(t, client) - _, workspace = runAgent(t, client, user.UserID) + client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user = coderdtest.CreateFirstUser(t, client) + workspace = runAgent(t, client, user.UserID) ) for _, c := range cases { //nolint:paralleltest // the `c := c` confuses the linter @@ -283,7 +283,7 @@ func TestPortForward(t *testing.T) { // runAgent creates a fake workspace and starts an agent locally for that // workspace. The agent will be cleaned up on test completion. // nolint:unused -func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) ([]codersdk.WorkspaceResource, codersdk.Workspace) { +func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk.Workspace { ctx := context.Background() user, err := client.User(ctx, userID.String()) require.NoError(t, err, "specified user does not exist") @@ -337,10 +337,8 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) ([]coders }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) - resources, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID) - require.NoError(t, err) - return resources, workspace + return workspace } // setupTestListener starts accepting connections and echoing a single packet. diff --git a/cli/show.go b/cli/show.go index 0035fabb7cc0a..9ed91d3e511a9 100644 --- a/cli/show.go +++ b/cli/show.go @@ -26,11 +26,7 @@ func show() *cobra.Command { if err != nil { return xerrors.Errorf("get workspace: %w", err) } - resources, err := client.WorkspaceResourcesByBuild(cmd.Context(), workspace.LatestBuild.ID) - if err != nil { - return xerrors.Errorf("get workspace resources: %w", err) - } - return cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{ + return cliui.WorkspaceResources(cmd.OutOrStdout(), workspace.LatestBuild.Resources, cliui.WorkspaceResourcesOptions{ WorkspaceName: workspace.Name, ServerVersion: buildInfo.Version, }) diff --git a/cli/speedtest_test.go b/cli/speedtest_test.go index fa432950d1db4..f210ebf6eef07 100644 --- a/cli/speedtest_test.go +++ b/cli/speedtest_test.go @@ -29,7 +29,7 @@ func TestSpeedtest(t *testing.T) { Logger: slogtest.Make(t, nil).Named("agent"), }) defer agentCloser.Close() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) cmd, root := clitest.New(t, "speedtest", workspace.Name) clitest.SetupConfig(t, client, root) diff --git a/cli/ssh.go b/cli/ssh.go index bb8922fb0ff71..ef8538764e3ac 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -261,10 +261,7 @@ func getWorkspaceAndAgent(ctx context.Context, cmd *cobra.Command, client *coder return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("workspace %q is being deleted", workspace.Name) } - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) - if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("fetch workspace resources: %w", err) - } + resources := workspace.LatestBuild.Resources agents := make([]codersdk.WorkspaceAgent, 0) for _, resource := range resources { diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 39c2f5fc6c5c8..cd776eccc403d 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -90,9 +90,9 @@ func TestWorkspaceActivityBump(t *testing.T) { client, workspace, assertBumped := setupActivityTest(t) - // Benign operations like retrieving resources must not + // Benign operations like retrieving workspace must not // bump the deadline. - _, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + _, err := client.Workspace(ctx, workspace.LatestBuild.ID) require.NoError(t, err) assertBumped(false) diff --git a/coderd/coderd.go b/coderd/coderd.go index 6d638324710e4..e79f862efafb4 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -449,14 +449,6 @@ func New(options *Options) *API { }) }) }) - r.Route("/workspaceresources/{workspaceresource}", func(r chi.Router) { - r.Use( - apiKeyMiddleware, - httpmw.ExtractWorkspaceResourceParam(options.Database), - httpmw.ExtractWorkspaceParam(options.Database), - ) - r.Get("/", api.workspaceResource) - }) r.Route("/workspaces", func(r chi.Router) { r.Use( apiKeyMiddleware, diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 60fca71cd0062..4ae47ebb11c13 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -100,10 +100,6 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { AssertAction: rbac.ActionUpdate, AssertObject: workspaceRBACObj, }, - "GET:/api/v2/workspaceresources/{workspaceresource}": { - AssertAction: rbac.ActionRead, - AssertObject: workspaceRBACObj, - }, "PATCH:/api/v2/workspacebuilds/{workspacebuild}/cancel": { AssertAction: rbac.ActionUpdate, AssertObject: workspaceRBACObj, @@ -351,7 +347,7 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) file, err := client.Upload(ctx, codersdk.ContentTypeTar, make([]byte, 1024)) require.NoError(t, err, "upload file") - workspaceResources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err = client.Workspace(ctx, workspace.ID) require.NoError(t, err, "workspace resources") templateVersionDryRun, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{ ParameterValues: []codersdk.CreateParameterRequest{}, @@ -372,16 +368,16 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a "{workspace}": workspace.ID.String(), "{workspacebuild}": workspace.LatestBuild.ID.String(), "{workspacename}": workspace.Name, - "{workspaceagent}": workspaceResources[0].Agents[0].ID.String(), + "{workspaceagent}": workspace.LatestBuild.Resources[0].Agents[0].ID.String(), "{buildnumber}": strconv.FormatInt(int64(workspace.LatestBuild.BuildNumber), 10), "{template}": template.ID.String(), "{hash}": file.Hash, - "{workspaceresource}": workspaceResources[0].ID.String(), - "{workspaceapp}": workspaceResources[0].Agents[0].Apps[0].Name, + "{workspaceresource}": workspace.LatestBuild.Resources[0].ID.String(), + "{workspaceapp}": workspace.LatestBuild.Resources[0].Agents[0].Apps[0].Name, "{templateversion}": version.ID.String(), "{jobID}": templateVersionDryRun.ID.String(), "{templatename}": template.Name, - "{workspace_and_agent}": workspace.Name + "." + workspaceResources[0].Agents[0].Name, + "{workspace_and_agent}": workspace.Name + "." + workspace.LatestBuild.Resources[0].Agents[0].Name, // Only checking template scoped params here "parameters/{scope}/{id}": fmt.Sprintf("parameters/%s/%s", string(templateParam.Scope), templateParam.ScopeID.String()), @@ -397,7 +393,7 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a Admin: admin, Template: template, Version: version, - WorkspaceResource: workspaceResources[0], + WorkspaceResource: workspace.LatestBuild.Resources[0], File: file, TemplateVersionDryRun: templateVersionDryRun, TemplateParam: templateParam, diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 72d08255f3bd3..31d1291a1278c 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -486,18 +486,18 @@ func AwaitWorkspaceBuildJob(t *testing.T, client *codersdk.Client, build uuid.UU } // AwaitWorkspaceAgents waits for all resources with agents to be connected. -func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, build uuid.UUID) []codersdk.WorkspaceResource { +func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID) []codersdk.WorkspaceResource { t.Helper() - t.Logf("waiting for workspace agents (build %s)", build) + t.Logf("waiting for workspace agents (workspace %s)", workspaceID) var resources []codersdk.WorkspaceResource require.Eventually(t, func() bool { var err error - resources, err = client.WorkspaceResourcesByBuild(context.Background(), build) + workspace, err := client.Workspace(context.Background(), workspaceID) if !assert.NoError(t, err) { return false } - for _, resource := range resources { + for _, resource := range workspace.LatestBuild.Resources { for _, agent := range resource.Agents { if agent.Status != codersdk.WorkspaceAgentConnected { t.Logf("agent %s not connected yet", agent.Name) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index d0ca0e897781a..e359b43da8755 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -61,10 +61,10 @@ func TestWorkspaceAgent(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) - require.Equal(t, tmpDir, resources[0].Agents[0].Directory) - _, err = client.WorkspaceAgent(ctx, resources[0].Agents[0].ID) + require.Equal(t, tmpDir, workspace.LatestBuild.Resources[0].Agents[0].Directory) + _, err = client.WorkspaceAgent(ctx, workspace.LatestBuild.Resources[0].Agents[0].ID) require.NoError(t, err) }) } diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 61ed5f984062a..3d796c0f76e73 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -393,13 +393,13 @@ func TestWorkspaceBuildResources(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) + workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) - require.NotNil(t, resources) - require.Len(t, resources, 2) - require.Equal(t, "some", resources[1].Name) - require.Equal(t, "example", resources[1].Type) - require.Len(t, resources[1].Agents, 1) + require.NotNil(t, workspace.LatestBuild.Resources) + require.Len(t, workspace.LatestBuild.Resources, 2) + require.Equal(t, "some", workspace.LatestBuild.Resources[1].Name) + require.Equal(t, "example", workspace.LatestBuild.Resources[1].Type) + require.Len(t, workspace.LatestBuild.Resources[1].Agents, 1) }) } diff --git a/coderd/workspaceresources.go b/coderd/workspaceresources.go deleted file mode 100644 index 0cb9f687e683b..0000000000000 --- a/coderd/workspaceresources.go +++ /dev/null @@ -1,98 +0,0 @@ -package coderd - -import ( - "database/sql" - "errors" - "net/http" - "sort" - - "github.com/google/uuid" - - "github.com/coder/coder/coderd/database" - "github.com/coder/coder/coderd/httpapi" - "github.com/coder/coder/coderd/httpmw" - "github.com/coder/coder/coderd/rbac" - "github.com/coder/coder/codersdk" -) - -func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - workspaceBuild := httpmw.WorkspaceBuildParam(r) - workspaceResource := httpmw.WorkspaceResourceParam(r) - workspace := httpmw.WorkspaceParam(r) - if !api.Authorize(r, rbac.ActionRead, workspace) { - httpapi.ResourceNotFound(rw) - return - } - - job, err := api.Database.GetProvisionerJobByID(ctx, workspaceBuild.JobID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching provisioner job.", - Detail: err.Error(), - }) - return - } - if !job.CompletedAt.Valid { - httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{ - Message: "Job hasn't completed!", - }) - return - } - agents, err := api.Database.GetWorkspaceAgentsByResourceIDs(ctx, []uuid.UUID{workspaceResource.ID}) - if errors.Is(err, sql.ErrNoRows) { - err = nil - } - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching provisioner job agents.", - Detail: err.Error(), - }) - return - } - agentIDs := make([]uuid.UUID, 0) - for _, agent := range agents { - agentIDs = append(agentIDs, agent.ID) - } - apps, err := api.Database.GetWorkspaceAppsByAgentIDs(ctx, agentIDs) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching workspace agent applications.", - Detail: err.Error(), - }) - return - } - apiAgents := make([]codersdk.WorkspaceAgent, 0) - for _, agent := range agents { - dbApps := make([]database.WorkspaceApp, 0) - for _, app := range apps { - if app.AgentID == agent.ID { - dbApps = append(dbApps, app) - } - } - - convertedAgent, err := convertWorkspaceAgent(api.DERPMap, api.TailnetCoordinator, agent, convertApps(dbApps), api.AgentInactiveDisconnectTimeout) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error reading workspace agent.", - Detail: err.Error(), - }) - return - } - apiAgents = append(apiAgents, convertedAgent) - } - sort.Slice(apiAgents, func(i, j int) bool { - return apiAgents[i].Name < apiAgents[j].Name - }) - - metadata, err := api.Database.GetWorkspaceResourceMetadataByResourceID(ctx, workspaceResource.ID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching workspace resource metadata.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, convertWorkspaceResource(workspaceResource, apiAgents, metadata)) -} diff --git a/coderd/workspaceresources_test.go b/coderd/workspaceresources_test.go deleted file mode 100644 index 6fd0f97fb5e57..0000000000000 --- a/coderd/workspaceresources_test.go +++ /dev/null @@ -1,212 +0,0 @@ -package coderd_test - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/coder/coder/coderd/coderdtest" - "github.com/coder/coder/codersdk" - "github.com/coder/coder/provisioner/echo" - "github.com/coder/coder/provisionersdk/proto" - "github.com/coder/coder/testutil" -) - -func TestWorkspaceResource(t *testing.T) { - t.Parallel() - t.Run("Get", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - Provision: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "beta", - Type: "example", - Icon: "/icon/server.svg", - Agents: []*proto.Agent{{ - Id: "something", - Name: "b", - Auth: &proto.Agent_Token{}, - }, { - Id: "another", - Name: "a", - Auth: &proto.Agent_Token{}, - }}, - }, { - Name: "alpha", - Type: "example", - }}, - }, - }, - }}, - }) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) - require.NoError(t, err) - // Ensure it's sorted alphabetically! - require.Equal(t, "alpha", resources[0].Name) - require.Equal(t, "beta", resources[1].Name) - resource, err := client.WorkspaceResource(ctx, resources[1].ID) - require.NoError(t, err) - require.Len(t, resource.Agents, 2) - // Ensure agents are sorted alphabetically! - require.Equal(t, "a", resource.Agents[0].Name) - require.Equal(t, "b", resource.Agents[1].Name) - // Ensure Icon is present - require.Equal(t, "/icon/server.svg", resources[1].Icon) - }) - - t.Run("Apps", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{ - IncludeProvisionerDaemon: true, - }) - user := coderdtest.CreateFirstUser(t, client) - apps := []*proto.App{ - { - Name: "code-server", - Command: "some-command", - Url: "http://localhost:3000", - Icon: "/code.svg", - }, - { - Name: "code-server-2", - Command: "some-command", - Url: "http://localhost:3000", - Icon: "/code.svg", - Healthcheck: &proto.Healthcheck{ - Url: "http://localhost:3000", - Interval: 5, - Threshold: 6, - }, - }, - } - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - Provision: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "some", - Type: "example", - Agents: []*proto.Agent{{ - Id: "something", - Auth: &proto.Agent_Token{}, - Apps: apps, - }}, - }}, - }, - }, - }}, - }) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) - require.NoError(t, err) - resource, err := client.WorkspaceResource(ctx, resources[0].ID) - require.NoError(t, err) - require.Len(t, resource.Agents, 1) - agent := resource.Agents[0] - require.Len(t, agent.Apps, 2) - got := agent.Apps[0] - app := apps[0] - require.EqualValues(t, app.Command, got.Command) - require.EqualValues(t, app.Icon, got.Icon) - require.EqualValues(t, app.Name, got.Name) - require.EqualValues(t, codersdk.WorkspaceAppHealthDisabled, got.Health) - require.EqualValues(t, "", got.Healthcheck.URL) - require.EqualValues(t, 0, got.Healthcheck.Interval) - require.EqualValues(t, 0, got.Healthcheck.Threshold) - got = agent.Apps[1] - app = apps[1] - require.EqualValues(t, app.Command, got.Command) - require.EqualValues(t, app.Icon, got.Icon) - require.EqualValues(t, app.Name, got.Name) - require.EqualValues(t, codersdk.WorkspaceAppHealthInitializing, got.Health) - require.EqualValues(t, app.Healthcheck.Url, got.Healthcheck.URL) - require.EqualValues(t, app.Healthcheck.Interval, got.Healthcheck.Interval) - require.EqualValues(t, app.Healthcheck.Threshold, got.Healthcheck.Threshold) - }) - - t.Run("Metadata", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{ - IncludeProvisionerDaemon: true, - }) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - Provision: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "some", - Type: "example", - Agents: []*proto.Agent{{ - Id: "something", - Auth: &proto.Agent_Token{}, - }}, - Metadata: []*proto.Resource_Metadata{{ - Key: "foo", - Value: "bar", - }, { - Key: "null", - IsNull: true, - }, { - Key: "empty", - }, { - Key: "secret", - Value: "squirrel", - Sensitive: true, - }}, - }}, - }, - }, - }}, - }) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID) - require.NoError(t, err) - resource, err := client.WorkspaceResource(ctx, resources[0].ID) - require.NoError(t, err) - metadata := resource.Metadata - require.Equal(t, []codersdk.WorkspaceResourceMetadata{{ - Key: "empty", - }, { - Key: "foo", - Value: "bar", - }, { - Key: "secret", - Value: "squirrel", - Sensitive: true, - }, { - Key: "type", - Value: "example", - }}, metadata) - }) -} diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index c94c4dd277bfb..ce414eeb1819f 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -1265,3 +1265,189 @@ func mustLocation(t *testing.T, location string) *time.Location { return loc } + +func TestWorkspaceResource(t *testing.T) { + t.Parallel() + t.Run("Get", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "beta", + Type: "example", + Icon: "/icon/server.svg", + Agents: []*proto.Agent{{ + Id: "something", + Name: "b", + Auth: &proto.Agent_Token{}, + }, { + Id: "another", + Name: "a", + Auth: &proto.Agent_Token{}, + }}, + }, { + Name: "alpha", + Type: "example", + }}, + }, + }, + }}, + }) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + workspace, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + require.Len(t, workspace.LatestBuild.Resources[0].Agents, 2) + // Ensure Icon is present + require.Equal(t, "/icon/server.svg", workspace.LatestBuild.Resources[0].Icon) + }) + + t.Run("Apps", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{ + IncludeProvisionerDaemon: true, + }) + user := coderdtest.CreateFirstUser(t, client) + apps := []*proto.App{ + { + Name: "code-server", + Command: "some-command", + Url: "http://localhost:3000", + Icon: "/code.svg", + }, + { + Name: "code-server-2", + Command: "some-command", + Url: "http://localhost:3000", + Icon: "/code.svg", + Healthcheck: &proto.Healthcheck{ + Url: "http://localhost:3000", + Interval: 5, + Threshold: 6, + }, + }, + } + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "some", + Type: "example", + Agents: []*proto.Agent{{ + Id: "something", + Auth: &proto.Agent_Token{}, + Apps: apps, + }}, + }}, + }, + }, + }}, + }) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + workspace, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + require.Len(t, workspace.LatestBuild.Resources[0].Agents, 1) + agent := workspace.LatestBuild.Resources[0].Agents[0] + require.Len(t, agent.Apps, 2) + got := agent.Apps[0] + app := apps[0] + require.EqualValues(t, app.Command, got.Command) + require.EqualValues(t, app.Icon, got.Icon) + require.EqualValues(t, app.Name, got.Name) + require.EqualValues(t, codersdk.WorkspaceAppHealthDisabled, got.Health) + require.EqualValues(t, "", got.Healthcheck.URL) + require.EqualValues(t, 0, got.Healthcheck.Interval) + require.EqualValues(t, 0, got.Healthcheck.Threshold) + got = agent.Apps[1] + app = apps[1] + require.EqualValues(t, app.Command, got.Command) + require.EqualValues(t, app.Icon, got.Icon) + require.EqualValues(t, app.Name, got.Name) + require.EqualValues(t, codersdk.WorkspaceAppHealthInitializing, got.Health) + require.EqualValues(t, app.Healthcheck.Url, got.Healthcheck.URL) + require.EqualValues(t, app.Healthcheck.Interval, got.Healthcheck.Interval) + require.EqualValues(t, app.Healthcheck.Threshold, got.Healthcheck.Threshold) + }) + + t.Run("Metadata", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{ + IncludeProvisionerDaemon: true, + }) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "some", + Type: "example", + Agents: []*proto.Agent{{ + Id: "something", + Auth: &proto.Agent_Token{}, + }}, + Metadata: []*proto.Resource_Metadata{{ + Key: "foo", + Value: "bar", + }, { + Key: "null", + IsNull: true, + }, { + Key: "empty", + }, { + Key: "secret", + Value: "squirrel", + Sensitive: true, + }}, + }}, + }, + }, + }}, + }) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + workspace, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + metadata := workspace.LatestBuild.Resources[0].Metadata + require.Equal(t, []codersdk.WorkspaceResourceMetadata{{ + Key: "empty", + }, { + Key: "foo", + Value: "bar", + }, { + Key: "secret", + Value: "squirrel", + Sensitive: true, + }, { + Key: "type", + Value: "example", + }}, metadata) + }) +} diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index 6979aaf46bd71..7b264aa4ae6ce 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -26,6 +26,61 @@ import ( "github.com/coder/retry" ) +type WorkspaceAgentStatus string + +const ( + WorkspaceAgentConnecting WorkspaceAgentStatus = "connecting" + WorkspaceAgentConnected WorkspaceAgentStatus = "connected" + WorkspaceAgentDisconnected WorkspaceAgentStatus = "disconnected" +) + +type WorkspaceAgent struct { + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + FirstConnectedAt *time.Time `json:"first_connected_at,omitempty"` + LastConnectedAt *time.Time `json:"last_connected_at,omitempty"` + DisconnectedAt *time.Time `json:"disconnected_at,omitempty"` + Status WorkspaceAgentStatus `json:"status"` + Name string `json:"name"` + ResourceID uuid.UUID `json:"resource_id"` + InstanceID string `json:"instance_id,omitempty"` + Architecture string `json:"architecture"` + EnvironmentVariables map[string]string `json:"environment_variables"` + OperatingSystem string `json:"operating_system"` + StartupScript string `json:"startup_script,omitempty"` + Directory string `json:"directory,omitempty"` + Version string `json:"version"` + Apps []WorkspaceApp `json:"apps"` + // DERPLatency is mapped by region name (e.g. "New York City", "Seattle"). + DERPLatency map[string]DERPRegion `json:"latency,omitempty"` +} + +type WorkspaceAgentResourceMetadata struct { + MemoryTotal uint64 `json:"memory_total"` + DiskTotal uint64 `json:"disk_total"` + CPUCores uint64 `json:"cpu_cores"` + CPUModel string `json:"cpu_model"` + CPUMhz float64 `json:"cpu_mhz"` +} + +type DERPRegion struct { + Preferred bool `json:"preferred"` + LatencyMilliseconds float64 `json:"latency_ms"` +} + +type WorkspaceAgentInstanceMetadata struct { + JailOrchestrator string `json:"jail_orchestrator"` + OperatingSystem string `json:"operating_system"` + Platform string `json:"platform"` + PlatformFamily string `json:"platform_family"` + KernelVersion string `json:"kernel_version"` + KernelArchitecture string `json:"kernel_architecture"` + Cloud string `json:"cloud"` + Jail string `json:"jail"` + VNC bool `json:"vnc"` +} + // @typescript-ignore GoogleInstanceIdentityToken type GoogleInstanceIdentityToken struct { JSONWebToken string `json:"json_web_token" validate:"required"` diff --git a/codersdk/workspacebuilds.go b/codersdk/workspacebuilds.go index 725f73a5053cd..b9241d09ecafc 100644 --- a/codersdk/workspacebuilds.go +++ b/codersdk/workspacebuilds.go @@ -70,6 +70,25 @@ type WorkspaceBuild struct { Status WorkspaceStatus `json:"status"` } +type WorkspaceResource struct { + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + JobID uuid.UUID `json:"job_id"` + Transition WorkspaceTransition `json:"workspace_transition"` + Type string `json:"type"` + Name string `json:"name"` + Hide bool `json:"hide"` + Icon string `json:"icon"` + Agents []WorkspaceAgent `json:"agents,omitempty"` + Metadata []WorkspaceResourceMetadata `json:"metadata,omitempty"` +} + +type WorkspaceResourceMetadata struct { + Key string `json:"key"` + Value string `json:"value"` + Sensitive bool `json:"sensitive"` +} + // WorkspaceBuild returns a single workspace build for a workspace. // If history is "", the latest version is returned. func (c *Client) WorkspaceBuild(ctx context.Context, id uuid.UUID) (WorkspaceBuild, error) { @@ -98,20 +117,6 @@ func (c *Client) CancelWorkspaceBuild(ctx context.Context, id uuid.UUID) error { return nil } -// WorkspaceResourcesByBuild returns resources for a workspace build. -func (c *Client) WorkspaceResourcesByBuild(ctx context.Context, build uuid.UUID) ([]WorkspaceResource, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspacebuilds/%s/resources", build), nil) - if err != nil { - return nil, err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return nil, readBodyAsError(res) - } - var resources []WorkspaceResource - return resources, json.NewDecoder(res.Body).Decode(&resources) -} - // WorkspaceBuildLogsBefore returns logs that occurred before a specific time. func (c *Client) WorkspaceBuildLogsBefore(ctx context.Context, build uuid.UUID, before time.Time) ([]ProvisionerJobLog, error) { return c.provisionerJobLogsBefore(ctx, fmt.Sprintf("/api/v2/workspacebuilds/%s/logs", build), before) diff --git a/codersdk/workspaceresources.go b/codersdk/workspaceresources.go deleted file mode 100644 index 3f306312fec19..0000000000000 --- a/codersdk/workspaceresources.go +++ /dev/null @@ -1,98 +0,0 @@ -package codersdk - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "time" - - "github.com/google/uuid" -) - -type WorkspaceAgentStatus string - -const ( - WorkspaceAgentConnecting WorkspaceAgentStatus = "connecting" - WorkspaceAgentConnected WorkspaceAgentStatus = "connected" - WorkspaceAgentDisconnected WorkspaceAgentStatus = "disconnected" -) - -type WorkspaceResource struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - JobID uuid.UUID `json:"job_id"` - Transition WorkspaceTransition `json:"workspace_transition"` - Type string `json:"type"` - Name string `json:"name"` - Hide bool `json:"hide"` - Icon string `json:"icon"` - Agents []WorkspaceAgent `json:"agents,omitempty"` - Metadata []WorkspaceResourceMetadata `json:"metadata,omitempty"` -} - -type WorkspaceResourceMetadata struct { - Key string `json:"key"` - Value string `json:"value"` - Sensitive bool `json:"sensitive"` -} - -type DERPRegion struct { - Preferred bool `json:"preferred"` - LatencyMilliseconds float64 `json:"latency_ms"` -} - -type WorkspaceAgent struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - FirstConnectedAt *time.Time `json:"first_connected_at,omitempty"` - LastConnectedAt *time.Time `json:"last_connected_at,omitempty"` - DisconnectedAt *time.Time `json:"disconnected_at,omitempty"` - Status WorkspaceAgentStatus `json:"status"` - Name string `json:"name"` - ResourceID uuid.UUID `json:"resource_id"` - InstanceID string `json:"instance_id,omitempty"` - Architecture string `json:"architecture"` - EnvironmentVariables map[string]string `json:"environment_variables"` - OperatingSystem string `json:"operating_system"` - StartupScript string `json:"startup_script,omitempty"` - Directory string `json:"directory,omitempty"` - Version string `json:"version"` - Apps []WorkspaceApp `json:"apps"` - // DERPLatency is mapped by region name (e.g. "New York City", "Seattle"). - DERPLatency map[string]DERPRegion `json:"latency,omitempty"` -} - -type WorkspaceAgentResourceMetadata struct { - MemoryTotal uint64 `json:"memory_total"` - DiskTotal uint64 `json:"disk_total"` - CPUCores uint64 `json:"cpu_cores"` - CPUModel string `json:"cpu_model"` - CPUMhz float64 `json:"cpu_mhz"` -} - -type WorkspaceAgentInstanceMetadata struct { - JailOrchestrator string `json:"jail_orchestrator"` - OperatingSystem string `json:"operating_system"` - Platform string `json:"platform"` - PlatformFamily string `json:"platform_family"` - KernelVersion string `json:"kernel_version"` - KernelArchitecture string `json:"kernel_architecture"` - Cloud string `json:"cloud"` - Jail string `json:"jail"` - VNC bool `json:"vnc"` -} - -func (c *Client) WorkspaceResource(ctx context.Context, id uuid.UUID) (WorkspaceResource, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceresources/%s", id), nil) - if err != nil { - return WorkspaceResource{}, err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return WorkspaceResource{}, readBodyAsError(res) - } - var resource WorkspaceResource - return resource, json.NewDecoder(res.Body).Decode(&resource) -} diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 5aaec5bda4458..dada75da0503a 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -264,15 +264,6 @@ export const getWorkspaceByOwnerAndName = async ( return response.data } -export const getWorkspaceResources = async ( - workspaceBuildID: string, -): Promise => { - const response = await axios.get( - `/api/v2/workspacebuilds/${workspaceBuildID}/resources`, - ) - return response.data -} - const postWorkspaceBuild = (transition: WorkspaceBuildTransition) => async (workspaceId: string, template_version_id?: string): Promise => { diff --git a/site/src/xServices/terminal/terminalXService.ts b/site/src/xServices/terminal/terminalXService.ts index d68bc218015a9..87d16832e7938 100644 --- a/site/src/xServices/terminal/terminalXService.ts +++ b/site/src/xServices/terminal/terminalXService.ts @@ -148,9 +148,7 @@ export const terminalMachine = throw new Error("workspace or workspace name is not set") } - const resources = await API.getWorkspaceResources(context.workspace.latest_build.id) - - const agent = resources + const agent = context.workspace.latest_build.resources .map((resource) => { if (!resource.agents || resource.agents.length === 0) { return From 08f7a330c804b202855a348e82f383831dda9286 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 19:03:08 +0000 Subject: [PATCH 2/8] fix --- coderd/activitybump_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index cd776eccc403d..1d59cbb239b70 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -92,7 +92,7 @@ func TestWorkspaceActivityBump(t *testing.T) { // Benign operations like retrieving workspace must not // bump the deadline. - _, err := client.Workspace(ctx, workspace.LatestBuild.ID) + _, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) assertBumped(false) From 1a442ac4493abcbc8f945eb1b6db13d2cae882ac Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 19:57:41 +0000 Subject: [PATCH 3/8] fix test --- cli/agent_test.go | 6 +++--- cli/configssh_test.go | 2 +- cli/gitssh_test.go | 2 +- cli/portforward_test.go | 2 +- coderd/activitybump_test.go | 4 ++-- coderd/coderdtest/coderdtest.go | 6 ++++++ coderd/coderdtest/coderdtest_test.go | 2 +- coderd/templates_test.go | 2 +- coderd/workspaceagents_test.go | 7 +++---- coderd/workspaceapps_test.go | 2 +- enterprise/coderd/workspaceagents_test.go | 2 +- 11 files changed, 21 insertions(+), 16 deletions(-) diff --git a/cli/agent_test.go b/cli/agent_test.go index 0bd65c63a62e4..dd0cb1d789349 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -60,7 +60,7 @@ func TestWorkspaceAgent(t *testing.T) { ctx := context.WithValue(ctx, "azure-client", metadataClient) errC <- cmd.ExecuteContext(ctx) }() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) resources := workspace.LatestBuild.Resources @@ -121,7 +121,7 @@ func TestWorkspaceAgent(t *testing.T) { ctx := context.WithValue(ctx, "aws-client", metadataClient) errC <- cmd.ExecuteContext(ctx) }() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) resources := workspace.LatestBuild.Resources @@ -182,7 +182,7 @@ func TestWorkspaceAgent(t *testing.T) { ctx := context.WithValue(ctx, "gcp-client", metadata) errC <- cmd.ExecuteContext(ctx) }() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) resources := workspace.LatestBuild.Resources diff --git a/cli/configssh_test.go b/cli/configssh_test.go index e1ae4054b5bea..3e1512a0c3471 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -114,7 +114,7 @@ func TestConfigSSH(t *testing.T) { defer func() { _ = agentCloser.Close() }() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) agentConn, err := client.DialWorkspaceAgentTailnet(context.Background(), slog.Logger{}, resources[0].Agents[0].ID) require.NoError(t, err) defer agentConn.Close() diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index db3224d03476f..566877a8c0429 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -81,7 +81,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*codersdk.Client, str errC <- cmd.ExecuteContext(ctx) }() t.Cleanup(func() { require.NoError(t, <-errC) }) - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) return agentClient, agentToken, pubkey } diff --git a/cli/portforward_test.go b/cli/portforward_test.go index 7f98ee38135c9..93719b2a13e5d 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -336,7 +336,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. errC <- cmd.ExecuteContext(agentCtx) }() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) return workspace } diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 1d59cbb239b70..b12c8bc170a29 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -36,7 +36,7 @@ func TestWorkspaceActivityBump(t *testing.T) { ) firstDeadline := workspace.LatestBuild.Deadline.Time - _ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + _ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) return client, workspace, func(want bool) { if !want { @@ -73,7 +73,7 @@ func TestWorkspaceActivityBump(t *testing.T) { client, workspace, assertBumped := setupActivityTest(t) - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) conn, err := client.DialWorkspaceAgentTailnet(ctx, slogtest.Make(t, nil), resources[0].Agents[0].ID) require.NoError(t, err) defer conn.Close() diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 31d1291a1278c..16d9c099fcf5a 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -497,6 +497,10 @@ func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, workspaceID uui if !assert.NoError(t, err) { return false } + if workspace.LatestBuild.Job.CompletedAt.IsZero() { + return false + } + for _, resource := range workspace.LatestBuild.Resources { for _, agent := range resource.Agents { if agent.Status != codersdk.WorkspaceAgentConnected { @@ -505,6 +509,8 @@ func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, workspaceID uui } } } + resources = workspace.LatestBuild.Resources + return true }, testutil.WaitLong, testutil.IntervalFast) return resources diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index b3dc8922a30b6..c0187fc94d661 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -23,7 +23,7 @@ func TestNew(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) _, _ = coderdtest.NewGoogleInstanceIdentity(t, "example", false) _, _ = coderdtest.NewAWSInstanceIdentity(t, "an-instance") } diff --git a/coderd/templates_test.go b/coderd/templates_test.go index 5052e4f9ba467..bf547c4d0eb9a 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -610,7 +610,7 @@ func TestTemplateDAUs(t *testing.T) { defer func() { _ = agentCloser.Close() }() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index e359b43da8755..f1261ba60dc1c 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -119,7 +119,7 @@ func TestWorkspaceAgentListen(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) conn, err := client.DialWorkspaceAgentTailnet(ctx, slog.Logger{}, resources[0].Agents[0].ID) require.NoError(t, err) defer func() { @@ -246,7 +246,7 @@ func TestWorkspaceAgentTailnet(t *testing.T) { Logger: slogtest.Make(t, nil).Named("agent").Leveled(slog.LevelDebug), }) defer agentCloser.Close() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -313,8 +313,7 @@ func TestWorkspaceAgentPTY(t *testing.T) { defer func() { _ = agentCloser.Close() }() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) - + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() diff --git a/coderd/workspaceapps_test.go b/coderd/workspaceapps_test.go index e111863f578df..e68061b185ec9 100644 --- a/coderd/workspaceapps_test.go +++ b/coderd/workspaceapps_test.go @@ -148,7 +148,7 @@ func setupProxyTest(t *testing.T, workspaceMutators ...func(*codersdk.CreateWork t.Cleanup(func() { _ = agentCloser.Close() }) - coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) // Configure the HTTP client to not follow redirects and to route all // requests regardless of hostname to the coderd test server. diff --git a/enterprise/coderd/workspaceagents_test.go b/enterprise/coderd/workspaceagents_test.go index 5b7c5b93b601d..3bb40b75b00f8 100644 --- a/enterprise/coderd/workspaceagents_test.go +++ b/enterprise/coderd/workspaceagents_test.go @@ -92,6 +92,6 @@ func setupWorkspaceAgent(t *testing.T, client *codersdk.Client, user codersdk.Cr defer func() { _ = agentCloser.Close() }() - resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID) + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) return resources[0].Agents[0].ID } From 09a3030dd1ba1fdb7b6c538a6bc51a67e97cd3cb Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 20:01:14 +0000 Subject: [PATCH 4/8] make gen --- site/src/api/typesGenerated.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 30f1f0a2d8e7c..67b5fc5c2f391 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -233,7 +233,7 @@ export interface DAUEntry { readonly amount: number } -// From codersdk/workspaceresources.go +// From codersdk/workspaceagents.go export interface DERPRegion { readonly preferred: boolean readonly latency_ms: number @@ -552,7 +552,7 @@ export interface Workspace { readonly last_used_at: string } -// From codersdk/workspaceresources.go +// From codersdk/workspaceagents.go export interface WorkspaceAgent { readonly id: string readonly created_at: string @@ -574,7 +574,7 @@ export interface WorkspaceAgent { readonly latency?: Record } -// From codersdk/workspaceresources.go +// From codersdk/workspaceagents.go export interface WorkspaceAgentInstanceMetadata { readonly jail_orchestrator: string readonly operating_system: string @@ -587,7 +587,7 @@ export interface WorkspaceAgentInstanceMetadata { readonly vnc: boolean } -// From codersdk/workspaceresources.go +// From codersdk/workspaceagents.go export interface WorkspaceAgentResourceMetadata { readonly memory_total: number readonly disk_total: number @@ -648,7 +648,7 @@ export interface WorkspaceQuota { readonly user_workspace_limit: number } -// From codersdk/workspaceresources.go +// From codersdk/workspacebuilds.go export interface WorkspaceResource { readonly id: string readonly created_at: string @@ -662,7 +662,7 @@ export interface WorkspaceResource { readonly metadata?: WorkspaceResourceMetadata[] } -// From codersdk/workspaceresources.go +// From codersdk/workspacebuilds.go export interface WorkspaceResourceMetadata { readonly key: string readonly value: string @@ -730,7 +730,7 @@ export type ServerSentEventType = "data" | "error" | "ping" // From codersdk/users.go export type UserStatus = "active" | "suspended" -// From codersdk/workspaceresources.go +// From codersdk/workspaceagents.go export type WorkspaceAgentStatus = "connected" | "connecting" | "disconnected" // From codersdk/workspaceapps.go From 05c0bb01ab298dd9d0de832ed31fbfd3b41707e8 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 20:16:17 +0000 Subject: [PATCH 5/8] fix test --- coderd/workspacebuilds_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 3d796c0f76e73..e61b5d8427285 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -397,7 +397,7 @@ func TestWorkspaceBuildResources(t *testing.T) { require.NoError(t, err) require.NotNil(t, workspace.LatestBuild.Resources) require.Len(t, workspace.LatestBuild.Resources, 2) - require.Equal(t, "some", workspace.LatestBuild.Resources[1].Name) + require.Equal(t, "some", workspace.LatestBuild.Resources[0].Name) require.Equal(t, "example", workspace.LatestBuild.Resources[1].Type) require.Len(t, workspace.LatestBuild.Resources[1].Agents, 1) }) From b63d71427f16b2932f7add44d499cfae68d438e1 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 20:16:51 +0000 Subject: [PATCH 6/8] fix test --- coderd/workspacebuilds_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index e61b5d8427285..1fbcd76b53d7c 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -399,7 +399,7 @@ func TestWorkspaceBuildResources(t *testing.T) { require.Len(t, workspace.LatestBuild.Resources, 2) require.Equal(t, "some", workspace.LatestBuild.Resources[0].Name) require.Equal(t, "example", workspace.LatestBuild.Resources[1].Type) - require.Len(t, workspace.LatestBuild.Resources[1].Agents, 1) + require.Len(t, workspace.LatestBuild.Resources[0].Agents, 1) }) } From 0f6d9c09aab93938cfce6ea9e9bd44d7639d85ba Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 20:29:21 +0000 Subject: [PATCH 7/8] fix js --- site/src/xServices/terminal/terminalXService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/src/xServices/terminal/terminalXService.ts b/site/src/xServices/terminal/terminalXService.ts index 87d16832e7938..5da4dc5019b04 100644 --- a/site/src/xServices/terminal/terminalXService.ts +++ b/site/src/xServices/terminal/terminalXService.ts @@ -148,7 +148,8 @@ export const terminalMachine = throw new Error("workspace or workspace name is not set") } - const agent = context.workspace.latest_build.resources + const newWorkspace = await API.getWorkspaceByOwnerAndName(context.username, context.workspaceName) + const agent = newWorkspace.latest_build.resources .map((resource) => { if (!resource.agents || resource.agents.length === 0) { return From 61b35e14fd1663b58c0a6d00c237db0ef29568c9 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 3 Oct 2022 20:52:35 +0000 Subject: [PATCH 8/8] fix js --- .../pages/TerminalPage/TerminalPage.test.tsx | 15 -- site/src/testHelpers/entities.ts | 244 +++++++++--------- .../xServices/terminal/terminalXService.ts | 3 +- 3 files changed, 123 insertions(+), 139 deletions(-) diff --git a/site/src/pages/TerminalPage/TerminalPage.test.tsx b/site/src/pages/TerminalPage/TerminalPage.test.tsx index 0ffae6188fe1b..80d024ff9a2b2 100644 --- a/site/src/pages/TerminalPage/TerminalPage.test.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.test.tsx @@ -69,21 +69,6 @@ describe("TerminalPage", () => { await expectTerminalText(container, Language.workspaceErrorMessagePrefix) }) - it("shows an error if fetching workspace agent fails", async () => { - // Given - server.use( - rest.get("/api/v2/workspacebuilds/:workspaceId/resources", (req, res, ctx) => { - return res(ctx.status(500), ctx.json({ message: "nope" })) - }), - ) - - // When - const { container } = renderTerminal() - - // Then - await expectTerminalText(container, Language.workspaceAgentErrorMessagePrefix) - }) - it("shows an error if the websocket fails", async () => { // Given server.use( diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index e464fe9b227d0..9e085883682f3 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -189,6 +189,127 @@ export const MockTemplate: TypesGen.Template = { icon: "/icon/code.svg", } +export const MockWorkspaceApp: TypesGen.WorkspaceApp = { + id: "test-app", + name: "test-app", + icon: "", + health: "disabled", + healthcheck: { + url: "", + interval: 0, + threshold: 0, + }, +} + +export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { + apps: [MockWorkspaceApp], + architecture: "amd64", + created_at: "", + environment_variables: {}, + id: "test-workspace-agent", + name: "a-workspace-agent", + operating_system: "linux", + resource_id: "", + status: "connected", + updated_at: "", + version: MockBuildInfo.version, + latency: { + "Coder Embedded DERP": { + latency_ms: 32.55, + preferred: true, + }, + }, +} + +export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-2", + name: "another-workspace-agent", + status: "disconnected", + version: "", + latency: {}, +} + +export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-3", + name: "an-outdated-workspace-agent", + version: "v99.999.9998+abcdef", + operating_system: "Windows", + latency: { + ...MockWorkspaceAgent.latency, + Chicago: { + preferred: false, + latency_ms: 95.11, + }, + "San Francisco": { + preferred: false, + latency_ms: 111.55, + }, + Paris: { + preferred: false, + latency_ms: 221.66, + }, + }, +} + +export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-connecting", + name: "another-workspace-agent", + status: "connecting", + version: "", + latency: {}, +} + +export const MockWorkspaceResource: TypesGen.WorkspaceResource = { + agents: [MockWorkspaceAgent, MockWorkspaceAgentConnecting, MockWorkspaceAgentOutdated], + created_at: "", + id: "test-workspace-resource", + job_id: "", + name: "a-workspace-resource", + type: "google_compute_disk", + workspace_transition: "start", + hide: false, + icon: "", + metadata: [ + { key: "type", value: "a-workspace-resource", sensitive: false }, + { key: "api_key", value: "12345678", sensitive: true }, + ], +} + +export const MockWorkspaceResource2: TypesGen.WorkspaceResource = { + agents: [MockWorkspaceAgent, MockWorkspaceAgentDisconnected, MockWorkspaceAgentOutdated], + created_at: "", + id: "test-workspace-resource-2", + job_id: "", + name: "another-workspace-resource", + type: "google_compute_disk", + workspace_transition: "start", + hide: false, + icon: "", + metadata: [ + { key: "type", value: "google_compute_disk", sensitive: false }, + { key: "size", value: "32GB", sensitive: false }, + ], +} + +export const MockWorkspaceResource3: TypesGen.WorkspaceResource = { + agents: [MockWorkspaceAgent, MockWorkspaceAgentDisconnected, MockWorkspaceAgentOutdated], + created_at: "", + id: "test-workspace-resource-3", + job_id: "", + name: "another-workspace-resource", + type: "google_compute_disk", + workspace_transition: "start", + hide: true, + icon: "", + metadata: [ + { key: "type", value: "google_compute_disk", sensitive: false }, + { key: "size", value: "32GB", sensitive: false }, + ], +} + export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { schedule: "", } @@ -215,7 +336,7 @@ export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = { workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3", deadline: "2022-05-17T23:39:00.00Z", reason: "initiator", - resources: [], + resources: [MockWorkspaceResource], status: "running", } @@ -333,127 +454,6 @@ export const MockWorkspaceRequest: TypesGen.CreateWorkspaceRequest = { template_id: "test-template", } -export const MockWorkspaceApp: TypesGen.WorkspaceApp = { - id: "test-app", - name: "test-app", - icon: "", - health: "disabled", - healthcheck: { - url: "", - interval: 0, - threshold: 0, - }, -} - -export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { - apps: [MockWorkspaceApp], - architecture: "amd64", - created_at: "", - environment_variables: {}, - id: "test-workspace-agent", - name: "a-workspace-agent", - operating_system: "linux", - resource_id: "", - status: "connected", - updated_at: "", - version: MockBuildInfo.version, - latency: { - "Coder Embedded DERP": { - latency_ms: 32.55, - preferred: true, - }, - }, -} - -export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { - ...MockWorkspaceAgent, - id: "test-workspace-agent-2", - name: "another-workspace-agent", - status: "disconnected", - version: "", - latency: {}, -} - -export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { - ...MockWorkspaceAgent, - id: "test-workspace-agent-3", - name: "an-outdated-workspace-agent", - version: "v99.999.9998+abcdef", - operating_system: "Windows", - latency: { - ...MockWorkspaceAgent.latency, - Chicago: { - preferred: false, - latency_ms: 95.11, - }, - "San Francisco": { - preferred: false, - latency_ms: 111.55, - }, - Paris: { - preferred: false, - latency_ms: 221.66, - }, - }, -} - -export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { - ...MockWorkspaceAgent, - id: "test-workspace-agent-connecting", - name: "another-workspace-agent", - status: "connecting", - version: "", - latency: {}, -} - -export const MockWorkspaceResource: TypesGen.WorkspaceResource = { - agents: [MockWorkspaceAgent, MockWorkspaceAgentConnecting, MockWorkspaceAgentOutdated], - created_at: "", - id: "test-workspace-resource", - job_id: "", - name: "a-workspace-resource", - type: "google_compute_disk", - workspace_transition: "start", - hide: false, - icon: "", - metadata: [ - { key: "type", value: "a-workspace-resource", sensitive: false }, - { key: "api_key", value: "12345678", sensitive: true }, - ], -} - -export const MockWorkspaceResource2: TypesGen.WorkspaceResource = { - agents: [MockWorkspaceAgent, MockWorkspaceAgentDisconnected, MockWorkspaceAgentOutdated], - created_at: "", - id: "test-workspace-resource-2", - job_id: "", - name: "another-workspace-resource", - type: "google_compute_disk", - workspace_transition: "start", - hide: false, - icon: "", - metadata: [ - { key: "type", value: "google_compute_disk", sensitive: false }, - { key: "size", value: "32GB", sensitive: false }, - ], -} - -export const MockWorkspaceResource3: TypesGen.WorkspaceResource = { - agents: [MockWorkspaceAgent, MockWorkspaceAgentDisconnected, MockWorkspaceAgentOutdated], - created_at: "", - id: "test-workspace-resource-3", - job_id: "", - name: "another-workspace-resource", - type: "google_compute_disk", - workspace_transition: "start", - hide: true, - icon: "", - metadata: [ - { key: "type", value: "google_compute_disk", sensitive: false }, - { key: "size", value: "32GB", sensitive: false }, - ], -} - export const MockUserAgent: Types.UserAgent = { browser: "Chrome 99.0.4844", device: "Other", diff --git a/site/src/xServices/terminal/terminalXService.ts b/site/src/xServices/terminal/terminalXService.ts index 5da4dc5019b04..87d16832e7938 100644 --- a/site/src/xServices/terminal/terminalXService.ts +++ b/site/src/xServices/terminal/terminalXService.ts @@ -148,8 +148,7 @@ export const terminalMachine = throw new Error("workspace or workspace name is not set") } - const newWorkspace = await API.getWorkspaceByOwnerAndName(context.username, context.workspaceName) - const agent = newWorkspace.latest_build.resources + const agent = context.workspace.latest_build.resources .map((resource) => { if (!resource.agents || resource.agents.length === 0) { return