Skip to content

Commit 82c8a3c

Browse files
committed
insert workspace modules on provisioner job completion
1 parent 0f713ed commit 82c8a3c

File tree

16 files changed

+531
-158
lines changed

16 files changed

+531
-158
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3222,6 +3222,13 @@ func (q *querier) InsertWorkspaceBuildParameters(ctx context.Context, arg databa
32223222
return q.db.InsertWorkspaceBuildParameters(ctx, arg)
32233223
}
32243224

3225+
func (q *querier) InsertWorkspaceModule(ctx context.Context, arg database.InsertWorkspaceModuleParams) (database.WorkspaceModule, error) {
3226+
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
3227+
return database.WorkspaceModule{}, err
3228+
}
3229+
return q.db.InsertWorkspaceModule(ctx, arg)
3230+
}
3231+
32253232
func (q *querier) InsertWorkspaceProxy(ctx context.Context, arg database.InsertWorkspaceProxyParams) (database.WorkspaceProxy, error) {
32263233
return insert(q.log, q.auth, rbac.ResourceWorkspaceProxy, q.db.InsertWorkspaceProxy)(ctx, arg)
32273234
}

coderd/database/dbmem/dbmem.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8233,6 +8233,15 @@ func (q *FakeQuerier) InsertWorkspaceBuildParameters(_ context.Context, arg data
82338233
return nil
82348234
}
82358235

8236+
func (q *FakeQuerier) InsertWorkspaceModule(ctx context.Context, arg database.InsertWorkspaceModuleParams) (database.WorkspaceModule, error) {
8237+
err := validateDatabaseType(arg)
8238+
if err != nil {
8239+
return database.WorkspaceModule{}, err
8240+
}
8241+
8242+
panic("not implemented")
8243+
}
8244+
82368245
func (q *FakeQuerier) InsertWorkspaceProxy(_ context.Context, arg database.InsertWorkspaceProxyParams) (database.WorkspaceProxy, error) {
82378246
q.mutex.Lock()
82388247
defer q.mutex.Unlock()

coderd/database/dbmetrics/querymetrics.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- name: InsertWorkspaceModule :one
2+
INSERT INTO
3+
workspace_modules (id, job_id, transition, source, version, key, created_at)
4+
VALUES
5+
($1, $2, $3, $4, $5, $6, $7) RETURNING *;

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,24 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
12671267
}
12681268
}
12691269
}
1270+
for transition, modules := range map[database.WorkspaceTransition][]*sdkproto.Module{
1271+
database.WorkspaceTransitionStart: jobType.TemplateImport.StartModules,
1272+
database.WorkspaceTransitionStop: jobType.TemplateImport.StopModules,
1273+
} {
1274+
for _, module := range modules {
1275+
s.Logger.Info(ctx, "inserting template import job module",
1276+
slog.F("job_id", job.ID.String()),
1277+
slog.F("module_source", module.Source),
1278+
slog.F("module_version", module.Version),
1279+
slog.F("module_key", module.Key),
1280+
slog.F("transition", transition))
1281+
1282+
err = InsertWorkspaceModule(ctx, s.Database, jobID, transition, module)
1283+
if err != nil {
1284+
return nil, xerrors.Errorf("insert module: %w", err)
1285+
}
1286+
}
1287+
}
12701288

12711289
for _, richParameter := range jobType.TemplateImport.RichParameters {
12721290
s.Logger.Info(ctx, "inserting template import job parameter",
@@ -1472,6 +1490,12 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
14721490
return xerrors.Errorf("insert provisioner job: %w", err)
14731491
}
14741492
}
1493+
for _, module := range jobType.WorkspaceBuild.Modules {
1494+
err = InsertWorkspaceModule(ctx, db, job.ID, workspaceBuild.Transition, module)
1495+
if err != nil {
1496+
return xerrors.Errorf("insert provisioner job module: %w", err)
1497+
}
1498+
}
14751499

14761500
// On start, we want to ensure that workspace agents timeout statuses
14771501
// are propagated. This method is simple and does not protect against
@@ -1653,6 +1677,17 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
16531677
return nil, xerrors.Errorf("insert resource: %w", err)
16541678
}
16551679
}
1680+
for _, module := range jobType.TemplateDryRun.Modules {
1681+
s.Logger.Info(ctx, "inserting template dry-run job module",
1682+
slog.F("job_id", job.ID.String()),
1683+
slog.F("module_source", module.Source),
1684+
)
1685+
1686+
err = InsertWorkspaceModule(ctx, s.Database, jobID, database.WorkspaceTransitionStart, module)
1687+
if err != nil {
1688+
return nil, xerrors.Errorf("insert module: %w", err)
1689+
}
1690+
}
16561691

16571692
err = s.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
16581693
ID: jobID,
@@ -1734,6 +1769,22 @@ func (s *server) startTrace(ctx context.Context, name string, opts ...trace.Span
17341769
))...)
17351770
}
17361771

1772+
func InsertWorkspaceModule(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoModule *sdkproto.Module) error {
1773+
_, err := db.InsertWorkspaceModule(ctx, database.InsertWorkspaceModuleParams{
1774+
ID: uuid.New(),
1775+
CreatedAt: dbtime.Now(),
1776+
JobID: jobID,
1777+
Transition: transition,
1778+
Source: protoModule.Source,
1779+
Version: protoModule.Version,
1780+
Key: protoModule.Key,
1781+
})
1782+
if err != nil {
1783+
return xerrors.Errorf("insert provisioner job module %q: %w", protoModule.Source, err)
1784+
}
1785+
return nil
1786+
}
1787+
17371788
func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource, snapshot *telemetry.Snapshot) error {
17381789
resource, err := db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{
17391790
ID: uuid.New(),

provisioner/terraform/modules.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package terraform
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"path/filepath"
7+
8+
"golang.org/x/xerrors"
9+
10+
"github.com/coder/coder/v2/provisionersdk/proto"
11+
)
12+
13+
type module struct {
14+
Source string `json:"Source"`
15+
Version string `json:"Version"`
16+
Key string `json:"Key"`
17+
}
18+
19+
type modulesFile struct {
20+
Modules []*module `json:"Modules"`
21+
}
22+
23+
func getModulesFilePath(workdir string) string {
24+
return filepath.Join(workdir, ".terraform", "modules", "modules.json")
25+
}
26+
27+
func parseModulesFile(filePath string) ([]*proto.Module, error) {
28+
modules := &modulesFile{}
29+
data, err := os.ReadFile(filePath)
30+
if err != nil {
31+
return nil, xerrors.Errorf("read modules file: %w", err)
32+
}
33+
if err := json.Unmarshal(data, modules); err != nil {
34+
return nil, xerrors.Errorf("unmarshal modules file: %w", err)
35+
}
36+
protoModules := make([]*proto.Module, len(modules.Modules))
37+
for i, m := range modules.Modules {
38+
protoModules[i] = &proto.Module{Source: m.Source, Version: m.Version, Key: m.Key}
39+
}
40+
return protoModules, nil
41+
}
42+
43+
// getModules returns the modules from the modules file if it exists.
44+
// It returns nil if the file does not exist.
45+
// Modules become available after terraform init.
46+
func getModules(workdir string) ([]*proto.Module, error) {
47+
filePath := getModulesFilePath(workdir)
48+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
49+
return nil, nil
50+
}
51+
return parseModulesFile(filePath)
52+
}

provisioner/terraform/provision.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ func (s *server) Plan(
142142
return provisionersdk.PlanErrorf("initialize terraform: %s", err)
143143
}
144144

145+
modules, err := getModules(sess.WorkDirectory)
146+
if err != nil {
147+
return provisionersdk.PlanErrorf("get modules: %s", err)
148+
}
149+
145150
initTimings.ingest(createInitTimingsEvent(timingInitComplete))
146151

147152
s.logger.Debug(ctx, "ran initialization")
@@ -167,6 +172,7 @@ func (s *server) Plan(
167172
// Prepend init timings since they occur prior to plan timings.
168173
// Order is irrelevant; this is merely indicative.
169174
resp.Timings = append(initTimings.aggregate(), resp.Timings...)
175+
resp.Modules = modules
170176
return resp
171177
}
172178

0 commit comments

Comments
 (0)