chore: remove resources calls (#4344)

This commit is contained in:
Garrett Delfosse 2022-10-03 17:01:13 -04:00 committed by GitHub
parent 9bc0d06aa0
commit 738a38d71f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 469 additions and 670 deletions

View File

@ -60,10 +60,11 @@ func TestWorkspaceAgent(t *testing.T) {
ctx := context.WithValue(ctx, "azure-client", metadataClient)
errC <- cmd.ExecuteContext(ctx)
}()
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID)
coderdtest.AwaitWorkspaceAgents(t, client, workspace.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)
@ -120,9 +121,10 @@ func TestWorkspaceAgent(t *testing.T) {
ctx := context.WithValue(ctx, "aws-client", metadataClient)
errC <- cmd.ExecuteContext(ctx)
}()
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID)
coderdtest.AwaitWorkspaceAgents(t, client, workspace.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)
}
@ -180,9 +182,10 @@ func TestWorkspaceAgent(t *testing.T) {
ctx := context.WithValue(ctx, "gcp-client", metadata)
errC <- cmd.ExecuteContext(ctx)
}()
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(ctx, workspace.LatestBuild.ID)
coderdtest.AwaitWorkspaceAgents(t, client, workspace.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)
}

View File

@ -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()

View File

@ -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
}

View File

@ -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")
@ -336,11 +336,9 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) ([]coders
errC <- cmd.ExecuteContext(agentCtx)
}()
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
require.NoError(t, err)
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
return resources, workspace
return workspace
}
// setupTestListener starts accepting connections and echoing a single packet.

View File

@ -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,
})

View File

@ -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)

View File

@ -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 {

View File

@ -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()
@ -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.ID)
require.NoError(t, err)
assertBumped(false)

View File

@ -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,

View File

@ -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,

View File

@ -486,18 +486,22 @@ 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 {
if workspace.LatestBuild.Job.CompletedAt.IsZero() {
return false
}
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)
@ -505,6 +509,8 @@ func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, build uuid.UUID
}
}
}
resources = workspace.LatestBuild.Resources
return true
}, testutil.WaitLong, testutil.IntervalFast)
return resources

View File

@ -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")
}

View File

@ -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()

View File

@ -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)
})
}
@ -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()

View File

@ -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.

View File

@ -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[0].Name)
require.Equal(t, "example", workspace.LatestBuild.Resources[1].Type)
require.Len(t, workspace.LatestBuild.Resources[0].Agents, 1)
})
}

View File

@ -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))
}

View File

@ -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)
})
}

View File

@ -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)
})
}

View File

@ -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"`

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -264,15 +264,6 @@ export const getWorkspaceByOwnerAndName = async (
return response.data
}
export const getWorkspaceResources = async (
workspaceBuildID: string,
): Promise<TypesGen.WorkspaceResource[]> => {
const response = await axios.get<TypesGen.WorkspaceResource[]>(
`/api/v2/workspacebuilds/${workspaceBuildID}/resources`,
)
return response.data
}
const postWorkspaceBuild =
(transition: WorkspaceBuildTransition) =>
async (workspaceId: string, template_version_id?: string): Promise<TypesGen.WorkspaceBuild> => {

View File

@ -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<string, DERPRegion>
}
// 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

View File

@ -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(

View File

@ -189,150 +189,6 @@ export const MockTemplate: TypesGen.Template = {
icon: "/icon/code.svg",
}
export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = {
schedule: "",
}
export const MockWorkspaceAutostartEnabled: TypesGen.UpdateWorkspaceAutostartRequest = {
// Runs at 9:30am Monday through Friday using Canada/Eastern
// (America/Toronto) time
schedule: "CRON_TZ=Canada/Eastern 30 9 * * 1-5",
}
export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = {
build_number: 1,
created_at: "2022-05-17T17:39:01.382927298Z",
id: "1",
initiator_id: MockUser.id,
initiator_name: MockUser.username,
job: MockProvisionerJob,
template_version_id: "",
transition: "start",
updated_at: "2022-05-17T17:39:01.382927298Z",
workspace_name: "test-workspace",
workspace_owner_id: MockUser.id,
workspace_owner_name: MockUser.username,
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
deadline: "2022-05-17T23:39:00.00Z",
reason: "initiator",
resources: [],
status: "running",
}
export const MockFailedWorkspaceBuild = (
transition: TypesGen.WorkspaceTransition = "start",
): TypesGen.WorkspaceBuild => ({
build_number: 1,
created_at: "2022-05-17T17:39:01.382927298Z",
id: "1",
initiator_id: MockUser.id,
initiator_name: MockUser.username,
job: MockFailedProvisionerJob,
template_version_id: "",
transition: transition,
updated_at: "2022-05-17T17:39:01.382927298Z",
workspace_name: "test-workspace",
workspace_owner_id: MockUser.id,
workspace_owner_name: MockUser.username,
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
deadline: "2022-05-17T23:39:00.00Z",
reason: "initiator",
resources: [],
status: "running",
})
export const MockWorkspaceBuildStop: TypesGen.WorkspaceBuild = {
...MockWorkspaceBuild,
id: "2",
transition: "stop",
}
export const MockWorkspaceBuildDelete: TypesGen.WorkspaceBuild = {
...MockWorkspaceBuild,
id: "3",
transition: "delete",
}
export const MockBuilds = [MockWorkspaceBuild, MockWorkspaceBuildStop, MockWorkspaceBuildDelete]
export const MockWorkspace: TypesGen.Workspace = {
id: "test-workspace",
name: "Test-Workspace",
created_at: "",
updated_at: "",
template_id: MockTemplate.id,
template_name: MockTemplate.name,
template_icon: MockTemplate.icon,
outdated: false,
owner_id: MockUser.id,
owner_name: MockUser.username,
autostart_schedule: MockWorkspaceAutostartEnabled.schedule,
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours as milliseconds
latest_build: MockWorkspaceBuild,
last_used_at: "",
}
export const MockStoppedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: MockWorkspaceBuildStop,
}
export const MockStoppingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuildStop,
job: MockRunningProvisionerJob,
},
}
export const MockStartingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockRunningProvisionerJob,
transition: "start",
},
}
export const MockCancelingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuild, job: MockCancelingProvisionerJob },
}
export const MockCanceledWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuild, job: MockCanceledProvisionerJob },
}
export const MockFailedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockFailedProvisionerJob,
},
}
export const MockDeletingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuildDelete, job: MockRunningProvisionerJob },
}
export const MockDeletedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: MockWorkspaceBuildDelete,
}
export const MockOutdatedWorkspace: TypesGen.Workspace = { ...MockFailedWorkspace, outdated: true }
export const MockQueuedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockPendingProvisionerJob,
transition: "start",
},
}
// requests the MockWorkspace
export const MockWorkspaceRequest: TypesGen.CreateWorkspaceRequest = {
name: "test",
parameter_values: [],
template_id: "test-template",
}
export const MockWorkspaceApp: TypesGen.WorkspaceApp = {
id: "test-app",
name: "test-app",
@ -454,6 +310,150 @@ export const MockWorkspaceResource3: TypesGen.WorkspaceResource = {
],
}
export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = {
schedule: "",
}
export const MockWorkspaceAutostartEnabled: TypesGen.UpdateWorkspaceAutostartRequest = {
// Runs at 9:30am Monday through Friday using Canada/Eastern
// (America/Toronto) time
schedule: "CRON_TZ=Canada/Eastern 30 9 * * 1-5",
}
export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = {
build_number: 1,
created_at: "2022-05-17T17:39:01.382927298Z",
id: "1",
initiator_id: MockUser.id,
initiator_name: MockUser.username,
job: MockProvisionerJob,
template_version_id: "",
transition: "start",
updated_at: "2022-05-17T17:39:01.382927298Z",
workspace_name: "test-workspace",
workspace_owner_id: MockUser.id,
workspace_owner_name: MockUser.username,
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
deadline: "2022-05-17T23:39:00.00Z",
reason: "initiator",
resources: [MockWorkspaceResource],
status: "running",
}
export const MockFailedWorkspaceBuild = (
transition: TypesGen.WorkspaceTransition = "start",
): TypesGen.WorkspaceBuild => ({
build_number: 1,
created_at: "2022-05-17T17:39:01.382927298Z",
id: "1",
initiator_id: MockUser.id,
initiator_name: MockUser.username,
job: MockFailedProvisionerJob,
template_version_id: "",
transition: transition,
updated_at: "2022-05-17T17:39:01.382927298Z",
workspace_name: "test-workspace",
workspace_owner_id: MockUser.id,
workspace_owner_name: MockUser.username,
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
deadline: "2022-05-17T23:39:00.00Z",
reason: "initiator",
resources: [],
status: "running",
})
export const MockWorkspaceBuildStop: TypesGen.WorkspaceBuild = {
...MockWorkspaceBuild,
id: "2",
transition: "stop",
}
export const MockWorkspaceBuildDelete: TypesGen.WorkspaceBuild = {
...MockWorkspaceBuild,
id: "3",
transition: "delete",
}
export const MockBuilds = [MockWorkspaceBuild, MockWorkspaceBuildStop, MockWorkspaceBuildDelete]
export const MockWorkspace: TypesGen.Workspace = {
id: "test-workspace",
name: "Test-Workspace",
created_at: "",
updated_at: "",
template_id: MockTemplate.id,
template_name: MockTemplate.name,
template_icon: MockTemplate.icon,
outdated: false,
owner_id: MockUser.id,
owner_name: MockUser.username,
autostart_schedule: MockWorkspaceAutostartEnabled.schedule,
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours as milliseconds
latest_build: MockWorkspaceBuild,
last_used_at: "",
}
export const MockStoppedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: MockWorkspaceBuildStop,
}
export const MockStoppingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuildStop,
job: MockRunningProvisionerJob,
},
}
export const MockStartingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockRunningProvisionerJob,
transition: "start",
},
}
export const MockCancelingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuild, job: MockCancelingProvisionerJob },
}
export const MockCanceledWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuild, job: MockCanceledProvisionerJob },
}
export const MockFailedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockFailedProvisionerJob,
},
}
export const MockDeletingWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: { ...MockWorkspaceBuildDelete, job: MockRunningProvisionerJob },
}
export const MockDeletedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: MockWorkspaceBuildDelete,
}
export const MockOutdatedWorkspace: TypesGen.Workspace = { ...MockFailedWorkspace, outdated: true }
export const MockQueuedWorkspace: TypesGen.Workspace = {
...MockWorkspace,
latest_build: {
...MockWorkspaceBuild,
job: MockPendingProvisionerJob,
transition: "start",
},
}
// requests the MockWorkspace
export const MockWorkspaceRequest: TypesGen.CreateWorkspaceRequest = {
name: "test",
parameter_values: [],
template_id: "test-template",
}
export const MockUserAgent: Types.UserAgent = {
browser: "Chrome 99.0.4844",
device: "Other",

View File

@ -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