Skip to content

Commit 6c902a7

Browse files
authored
fix: don't create autostart workspace builds with no available provisioners (#19067)
This should fix #17941 by introducing a check for whether there are any valid (non-stale provisioners for a job in the autobuild executor code path. --------- Signed-off-by: Callum Styan <callumstyan@gmail.com>
1 parent a25d856 commit 6c902a7

File tree

4 files changed

+476
-84
lines changed

4 files changed

+476
-84
lines changed

coderd/autobuild/lifecycle_executor.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/coder/coder/v2/coderd/database/provisionerjobs"
3030
"github.com/coder/coder/v2/coderd/database/pubsub"
3131
"github.com/coder/coder/v2/coderd/notifications"
32+
"github.com/coder/coder/v2/coderd/provisionerdserver"
3233
"github.com/coder/coder/v2/coderd/schedule"
3334
"github.com/coder/coder/v2/coderd/wsbuilder"
3435
"github.com/coder/coder/v2/codersdk"
@@ -132,6 +133,39 @@ func (e *Executor) Run() {
132133
})
133134
}
134135

136+
// hasValidProvisioner checks whether there is at least one valid (non-stale, correct tags) provisioner
137+
// based on time t and the tags maps (such as from a templateVersionJob).
138+
func (e *Executor) hasValidProvisioner(ctx context.Context, tx database.Store, t time.Time, ws database.Workspace, tags map[string]string) (bool, error) {
139+
queryParams := database.GetProvisionerDaemonsByOrganizationParams{
140+
OrganizationID: ws.OrganizationID,
141+
WantTags: tags,
142+
}
143+
144+
// nolint: gocritic // The user (in this case, the user/context for autostart builds) may not have the full
145+
// permissions to read provisioner daemons, but we need to check if there's any for the job prior to the
146+
// execution of the job via autostart to fix: https://github.com/coder/coder/issues/17941
147+
provisionerDaemons, err := tx.GetProvisionerDaemonsByOrganization(dbauthz.AsSystemReadProvisionerDaemons(ctx), queryParams)
148+
if err != nil {
149+
return false, xerrors.Errorf("get provisioner daemons: %w", err)
150+
}
151+
152+
logger := e.log.With(slog.F("tags", tags))
153+
// Check if any provisioners are active (not stale)
154+
for _, pd := range provisionerDaemons {
155+
if pd.LastSeenAt.Valid {
156+
age := t.Sub(pd.LastSeenAt.Time)
157+
if age <= provisionerdserver.StaleInterval {
158+
logger.Debug(ctx, "hasValidProvisioner: found active provisioner",
159+
slog.F("daemon_id", pd.ID),
160+
)
161+
return true, nil
162+
}
163+
}
164+
}
165+
logger.Debug(ctx, "hasValidProvisioner: no active provisioners found")
166+
return false, nil
167+
}
168+
135169
func (e *Executor) runOnce(t time.Time) Stats {
136170
stats := Stats{
137171
Transitions: make(map[uuid.UUID]database.WorkspaceTransition),
@@ -281,6 +315,22 @@ func (e *Executor) runOnce(t time.Time) Stats {
281315
return nil
282316
}
283317

318+
// Get the template version job to access tags
319+
templateVersionJob, err := tx.GetProvisionerJobByID(e.ctx, activeTemplateVersion.JobID)
320+
if err != nil {
321+
return xerrors.Errorf("get template version job: %w", err)
322+
}
323+
324+
// Before creating the workspace build, check for available provisioners
325+
hasProvisioners, err := e.hasValidProvisioner(e.ctx, tx, t, ws, templateVersionJob.Tags)
326+
if err != nil {
327+
return xerrors.Errorf("check provisioner availability: %w", err)
328+
}
329+
if !hasProvisioners {
330+
log.Warn(e.ctx, "skipping autostart - no available provisioners")
331+
return nil // Skip this workspace
332+
}
333+
284334
if nextTransition != "" {
285335
builder := wsbuilder.New(ws, nextTransition, *e.buildUsageChecker.Load()).
286336
SetLastWorkspaceBuildInTx(&latestBuild).

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy