mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): fix logic for reporting prebuilt workspace duration metric (#19641)
## Description When creating a prebuilt workspace, both `flags.IsPrebuild` and `flags.IsFirstBuild` are true. Previously, the logic rejected cases with multiple flags, so `coderd_workspace_creation_duration_seconds` wasn’t updated for prebuilt creations. This is the only valid scenario where two flags can be true. ## Changes * Fix logic to update `coderd_workspace_creation_duration_seconds` metric for prebuilt workspaces. * Add prebuild helper functions to coderdenttest (other prebuild tests can reuse this). * Update workspace's provisionerdmetric tests to include this metric. Follow-up: https://github.com/coder/coder/pull/19503 Related to: https://github.com/coder/coder/issues/19528
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"database/sql"
|
||||
"io"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
@@ -23,10 +24,13 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/coderd/prebuilds"
|
||||
"github.com/coder/coder/v2/coderd/util/ptr"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/codersdk/drpcsdk"
|
||||
"github.com/coder/coder/v2/enterprise/coderd"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/license"
|
||||
entprebuilds "github.com/coder/coder/v2/enterprise/coderd/prebuilds"
|
||||
"github.com/coder/coder/v2/enterprise/dbcrypt"
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
"github.com/coder/coder/v2/provisioner/terraform"
|
||||
@@ -446,3 +450,98 @@ func newExternalProvisionerDaemon(t testing.TB, client *codersdk.Client, org uui
|
||||
|
||||
return closer
|
||||
}
|
||||
|
||||
func GetRunningPrebuilds(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
db database.Store,
|
||||
desiredPrebuilds int,
|
||||
) []database.GetRunningPrebuiltWorkspacesRow {
|
||||
t.Helper()
|
||||
|
||||
var runningPrebuilds []database.GetRunningPrebuiltWorkspacesRow
|
||||
testutil.Eventually(ctx, t, func(context.Context) bool {
|
||||
prebuiltWorkspaces, err := db.GetRunningPrebuiltWorkspaces(ctx)
|
||||
assert.NoError(t, err, "failed to get running prebuilds")
|
||||
|
||||
for _, prebuild := range prebuiltWorkspaces {
|
||||
runningPrebuilds = append(runningPrebuilds, prebuild)
|
||||
|
||||
agents, err := db.GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx, prebuild.ID)
|
||||
assert.NoError(t, err, "failed to get agents")
|
||||
|
||||
// Manually mark all agents as ready since tests don't have real agent processes
|
||||
// that would normally report their lifecycle state. Prebuilt workspaces are only
|
||||
// eligible for claiming when their agents reach the "ready" state.
|
||||
for _, agent := range agents {
|
||||
err = db.UpdateWorkspaceAgentLifecycleStateByID(ctx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{
|
||||
ID: agent.ID,
|
||||
LifecycleState: database.WorkspaceAgentLifecycleStateReady,
|
||||
StartedAt: sql.NullTime{Time: time.Now().Add(time.Hour), Valid: true},
|
||||
ReadyAt: sql.NullTime{Time: time.Now().Add(-1 * time.Hour), Valid: true},
|
||||
})
|
||||
assert.NoError(t, err, "failed to update agent")
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("found %d running prebuilds so far, want %d", len(runningPrebuilds), desiredPrebuilds)
|
||||
return len(runningPrebuilds) == desiredPrebuilds
|
||||
}, testutil.IntervalSlow, "found %d running prebuilds, expected %d", len(runningPrebuilds), desiredPrebuilds)
|
||||
|
||||
return runningPrebuilds
|
||||
}
|
||||
|
||||
func MustRunReconciliationLoopForPreset(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
db database.Store,
|
||||
reconciler *entprebuilds.StoreReconciler,
|
||||
preset codersdk.Preset,
|
||||
) []*prebuilds.ReconciliationActions {
|
||||
t.Helper()
|
||||
|
||||
state, err := reconciler.SnapshotState(ctx, db)
|
||||
require.NoError(t, err)
|
||||
ps, err := state.FilterByPreset(preset.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ps)
|
||||
actions, err := reconciler.CalculateActions(ctx, *ps)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, actions)
|
||||
require.NoError(t, reconciler.ReconcilePreset(ctx, *ps))
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
func MustClaimPrebuild(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
client *codersdk.Client,
|
||||
userClient *codersdk.Client,
|
||||
username string,
|
||||
version codersdk.TemplateVersion,
|
||||
presetID uuid.UUID,
|
||||
autostartSchedule ...string,
|
||||
) codersdk.Workspace {
|
||||
t.Helper()
|
||||
|
||||
var startSchedule string
|
||||
if len(autostartSchedule) > 0 {
|
||||
startSchedule = autostartSchedule[0]
|
||||
}
|
||||
|
||||
workspaceName := strings.ReplaceAll(testutil.GetRandomName(t), "_", "-")
|
||||
userWorkspace, err := userClient.CreateUserWorkspace(ctx, username, codersdk.CreateWorkspaceRequest{
|
||||
TemplateVersionID: version.ID,
|
||||
Name: workspaceName,
|
||||
TemplateVersionPresetID: presetID,
|
||||
AutostartSchedule: ptr.Ref(startSchedule),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, userWorkspace.LatestBuild.ID)
|
||||
require.Equal(t, build.Job.Status, codersdk.ProvisionerJobSucceeded)
|
||||
workspace := coderdtest.MustWorkspace(t, client, userWorkspace.ID)
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
|
||||
|
||||
return workspace
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user