Skip to content

Commit cc11f71

Browse files
committed
Merge branch 'main' into bryphe/prototype/workspaces-page
2 parents dd38938 + c65850b commit cc11f71

39 files changed

+1721
-328
lines changed

.github/workflows/coder.yaml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ jobs:
7979
- uses: actions/setup-go@v2
8080
with:
8181
go-version: "^1.17"
82-
- run:
83-
curl -sSL
82+
- run: curl -sSL
8483
https://github.com/kyleconroy/sqlc/releases/download/v1.11.0/sqlc_1.11.0_linux_amd64.tar.gz
8584
| sudo tar -C /usr/bin -xz sqlc
8685

@@ -151,21 +150,18 @@ jobs:
151150
- run: go install gotest.tools/gotestsum@latest
152151

153152
- uses: hashicorp/setup-terraform@v1
154-
if: runner.os == 'Linux'
155153
with:
156154
terraform_version: 1.1.2
157155
terraform_wrapper: false
158156

159157
- name: Test with Mock Database
160-
run:
161-
gotestsum --jsonfile="gotests.json" --packages="./..." --
158+
run: gotestsum --jsonfile="gotests.json" --packages="./..." --
162159
-covermode=atomic -coverprofile="gotests.coverage" -timeout=3m
163-
-count=3 -race -short -parallel=2
160+
-count=5 -race -short -parallel=2
164161

165162
- name: Test with PostgreSQL Database
166163
if: runner.os == 'Linux'
167-
run:
168-
DB=true gotestsum --jsonfile="gotests.json" --packages="./..." --
164+
run: DB=true gotestsum --jsonfile="gotests.json" --packages="./..." --
169165
-covermode=atomic -coverprofile="gotests.coverage" -timeout=3m
170166
-count=1 -race -parallel=2
171167

.vscode/settings.json

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,32 @@
2323
}
2424
]
2525
},
26-
"cSpell.words": ["coderd", "coderdtest", "codersdk", "httpmw", "oneof", "stretchr", "xerrors"]
26+
"cSpell.words": [
27+
"coderd",
28+
"coderdtest",
29+
"codersdk",
30+
"drpc",
31+
"drpcconn",
32+
"drpcmux",
33+
"drpcserver",
34+
"goleak",
35+
"hashicorp",
36+
"httpmw",
37+
"moby",
38+
"nhooyr",
39+
"nolint",
40+
"nosec",
41+
"oneof",
42+
"protobuf",
43+
"provisionerd",
44+
"provisionersdk",
45+
"retrier",
46+
"sdkproto",
47+
"stretchr",
48+
"tfexec",
49+
"tfstate",
50+
"unconvert",
51+
"xerrors",
52+
"yamux"
53+
]
2754
}

coderd/cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"cdr.dev/slog"
1212
"cdr.dev/slog/sloggers/sloghuman"
1313
"github.com/coder/coder/coderd"
14+
"github.com/coder/coder/database"
1415
"github.com/coder/coder/database/databasefake"
1516
)
1617

@@ -24,6 +25,7 @@ func Root() *cobra.Command {
2425
handler := coderd.New(&coderd.Options{
2526
Logger: slog.Make(sloghuman.Sink(os.Stderr)),
2627
Database: databasefake.New(),
28+
Pubsub: database.NewPubsubInMemory(),
2729
})
2830

2931
listener, err := net.Listen("tcp", address)

coderd/coderd.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Options struct {
2323
func New(options *Options) http.Handler {
2424
api := &api{
2525
Database: options.Database,
26+
Logger: options.Logger,
2627
Pubsub: options.Pubsub,
2728
}
2829

@@ -64,6 +65,10 @@ func New(options *Options) http.Handler {
6465
r.Route("/history", func(r chi.Router) {
6566
r.Get("/", api.projectHistoryByOrganization)
6667
r.Post("/", api.postProjectHistoryByOrganization)
68+
r.Route("/{projecthistory}", func(r chi.Router) {
69+
r.Use(httpmw.ExtractProjectHistoryParam(api.Database))
70+
r.Get("/", api.projectHistoryByOrganizationAndName)
71+
})
6772
})
6873
})
6974
})
@@ -84,11 +89,19 @@ func New(options *Options) http.Handler {
8489
r.Route("/history", func(r chi.Router) {
8590
r.Post("/", api.postWorkspaceHistoryByUser)
8691
r.Get("/", api.workspaceHistoryByUser)
87-
r.Get("/latest", api.latestWorkspaceHistoryByUser)
92+
r.Route("/{workspacehistory}", func(r chi.Router) {
93+
r.Use(httpmw.ExtractWorkspaceHistoryParam(options.Database))
94+
r.Get("/", api.workspaceHistoryByName)
95+
})
8896
})
8997
})
9098
})
9199
})
100+
101+
r.Route("/provisioners/daemons", func(r chi.Router) {
102+
r.Get("/", api.provisionerDaemons)
103+
r.Get("/serve", api.provisionerDaemonsServe)
104+
})
92105
})
93106
r.NotFound(site.Handler().ServeHTTP)
94107
return r
@@ -98,5 +111,6 @@ func New(options *Options) http.Handler {
98111
// be added to this struct for code clarity.
99112
type api struct {
100113
Database database.Store
114+
Logger slog.Logger
101115
Pubsub database.Pubsub
102116
}

coderd/coderdtest/coderdtest.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@ package coderdtest
33
import (
44
"context"
55
"database/sql"
6+
"io"
67
"net/http/httptest"
78
"net/url"
89
"os"
910
"testing"
11+
"time"
1012

1113
"github.com/stretchr/testify/require"
1214

15+
"cdr.dev/slog"
1316
"cdr.dev/slog/sloggers/slogtest"
1417
"github.com/coder/coder/coderd"
1518
"github.com/coder/coder/codersdk"
1619
"github.com/coder/coder/cryptorand"
1720
"github.com/coder/coder/database"
1821
"github.com/coder/coder/database/databasefake"
1922
"github.com/coder/coder/database/postgres"
23+
"github.com/coder/coder/provisioner/terraform"
24+
"github.com/coder/coder/provisionerd"
25+
"github.com/coder/coder/provisionersdk"
26+
"github.com/coder/coder/provisionersdk/proto"
2027
)
2128

2229
// Server represents a test instance of coderd.
@@ -57,11 +64,46 @@ func (s *Server) RandomInitialUser(t *testing.T) coderd.CreateInitialUserRequest
5764
return req
5865
}
5966

67+
// AddProvisionerd launches a new provisionerd instance!
68+
func (s *Server) AddProvisionerd(t *testing.T) io.Closer {
69+
tfClient, tfServer := provisionersdk.TransportPipe()
70+
ctx, cancelFunc := context.WithCancel(context.Background())
71+
t.Cleanup(func() {
72+
_ = tfClient.Close()
73+
_ = tfServer.Close()
74+
cancelFunc()
75+
})
76+
go func() {
77+
err := terraform.Serve(ctx, &terraform.ServeOptions{
78+
ServeOptions: &provisionersdk.ServeOptions{
79+
Listener: tfServer,
80+
},
81+
Logger: slogtest.Make(t, nil).Named("terraform-provisioner").Leveled(slog.LevelDebug),
82+
})
83+
require.NoError(t, err)
84+
}()
85+
86+
closer := provisionerd.New(s.Client.ProvisionerDaemonClient, &provisionerd.Options{
87+
Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug),
88+
PollInterval: 50 * time.Millisecond,
89+
UpdateInterval: 50 * time.Millisecond,
90+
Provisioners: provisionerd.Provisioners{
91+
string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(provisionersdk.Conn(tfClient)),
92+
},
93+
WorkDirectory: t.TempDir(),
94+
})
95+
t.Cleanup(func() {
96+
_ = closer.Close()
97+
})
98+
return closer
99+
}
100+
60101
// New constructs a new coderd test instance. This returned Server
61102
// should contain no side-effects.
62103
func New(t *testing.T) Server {
63104
// This can be hotswapped for a live database instance.
64105
db := databasefake.New()
106+
pubsub := database.NewPubsubInMemory()
65107
if os.Getenv("DB") != "" {
66108
connectionURL, close, err := postgres.Open()
67109
require.NoError(t, err)
@@ -74,11 +116,18 @@ func New(t *testing.T) Server {
74116
err = database.Migrate(sqlDB)
75117
require.NoError(t, err)
76118
db = database.New(sqlDB)
119+
120+
pubsub, err = database.NewPubsub(context.Background(), sqlDB, connectionURL)
121+
require.NoError(t, err)
122+
t.Cleanup(func() {
123+
_ = pubsub.Close()
124+
})
77125
}
78126

79127
handler := coderd.New(&coderd.Options{
80-
Logger: slogtest.Make(t, nil),
128+
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
81129
Database: db,
130+
Pubsub: pubsub,
82131
})
83132
srv := httptest.NewServer(handler)
84133
serverURL, err := url.Parse(srv.URL)

coderd/coderdtest/coderdtest_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ func TestNew(t *testing.T) {
1616
t.Parallel()
1717
server := coderdtest.New(t)
1818
_ = server.RandomInitialUser(t)
19+
_ = server.AddProvisionerd(t)
1920
}

coderd/projecthistory.go

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"archive/tar"
55
"bytes"
66
"database/sql"
7+
"encoding/json"
78
"errors"
89
"fmt"
910
"net/http"
@@ -12,6 +13,7 @@ import (
1213
"github.com/go-chi/render"
1314
"github.com/google/uuid"
1415
"github.com/moby/moby/pkg/namesgenerator"
16+
"golang.org/x/xerrors"
1517

1618
"github.com/coder/coder/database"
1719
"github.com/coder/coder/httpapi"
@@ -26,6 +28,7 @@ type ProjectHistory struct {
2628
UpdatedAt time.Time `json:"updated_at"`
2729
Name string `json:"name"`
2830
StorageMethod database.ProjectStorageMethod `json:"storage_method"`
31+
Import ProvisionerJob `json:"import"`
2932
}
3033

3134
// CreateProjectHistoryRequest enables callers to create a new Project Version.
@@ -50,12 +53,33 @@ func (api *api) projectHistoryByOrganization(rw http.ResponseWriter, r *http.Req
5053
}
5154
apiHistory := make([]ProjectHistory, 0)
5255
for _, version := range history {
53-
apiHistory = append(apiHistory, convertProjectHistory(version))
56+
job, err := api.Database.GetProvisionerJobByID(r.Context(), version.ImportJobID)
57+
if err != nil {
58+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
59+
Message: fmt.Sprintf("get provisioner job: %s", err),
60+
})
61+
return
62+
}
63+
apiHistory = append(apiHistory, convertProjectHistory(version, job))
5464
}
5565
render.Status(r, http.StatusOK)
5666
render.JSON(rw, r, apiHistory)
5767
}
5868

69+
// Return a single project history by organization and name.
70+
func (api *api) projectHistoryByOrganizationAndName(rw http.ResponseWriter, r *http.Request) {
71+
projectHistory := httpmw.ProjectHistoryParam(r)
72+
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectHistory.ImportJobID)
73+
if err != nil {
74+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
75+
Message: fmt.Sprintf("get provisioner job: %s", err),
76+
})
77+
return
78+
}
79+
render.Status(r, http.StatusOK)
80+
render.JSON(rw, r, convertProjectHistory(projectHistory, job))
81+
}
82+
5983
// Creates a new version of the project. An import job is queued to parse
6084
// the storage method provided. Once completed, the import job will specify
6185
// the version as latest.
@@ -82,37 +106,71 @@ func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http
82106
return
83107
}
84108

109+
apiKey := httpmw.APIKey(r)
85110
project := httpmw.ProjectParam(r)
86-
history, err := api.Database.InsertProjectHistory(r.Context(), database.InsertProjectHistoryParams{
87-
ID: uuid.New(),
88-
ProjectID: project.ID,
89-
CreatedAt: database.Now(),
90-
UpdatedAt: database.Now(),
91-
Name: namesgenerator.GetRandomName(1),
92-
StorageMethod: createProjectVersion.StorageMethod,
93-
StorageSource: createProjectVersion.StorageSource,
94-
// TODO: Make this do something!
95-
ImportJobID: uuid.New(),
111+
112+
var provisionerJob database.ProvisionerJob
113+
var projectHistory database.ProjectHistory
114+
err := api.Database.InTx(func(db database.Store) error {
115+
projectHistoryID := uuid.New()
116+
input, err := json.Marshal(projectImportJob{
117+
ProjectHistoryID: projectHistoryID,
118+
})
119+
if err != nil {
120+
return xerrors.Errorf("marshal import job: %w", err)
121+
}
122+
123+
provisionerJob, err = db.InsertProvisionerJob(r.Context(), database.InsertProvisionerJobParams{
124+
ID: uuid.New(),
125+
CreatedAt: database.Now(),
126+
UpdatedAt: database.Now(),
127+
InitiatorID: apiKey.UserID,
128+
Provisioner: project.Provisioner,
129+
Type: database.ProvisionerJobTypeProjectImport,
130+
ProjectID: project.ID,
131+
Input: input,
132+
})
133+
if err != nil {
134+
return xerrors.Errorf("insert provisioner job: %w", err)
135+
}
136+
137+
projectHistory, err = api.Database.InsertProjectHistory(r.Context(), database.InsertProjectHistoryParams{
138+
ID: projectHistoryID,
139+
ProjectID: project.ID,
140+
CreatedAt: database.Now(),
141+
UpdatedAt: database.Now(),
142+
Name: namesgenerator.GetRandomName(1),
143+
StorageMethod: createProjectVersion.StorageMethod,
144+
StorageSource: createProjectVersion.StorageSource,
145+
ImportJobID: provisionerJob.ID,
146+
})
147+
if err != nil {
148+
return xerrors.Errorf("insert project history: %s", err)
149+
}
150+
return nil
96151
})
97152
if err != nil {
98153
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
99-
Message: fmt.Sprintf("insert project history: %s", err),
154+
Message: err.Error(),
100155
})
101156
return
102157
}
103158

104-
// TODO: A job to process the new version should occur here.
105-
106159
render.Status(r, http.StatusCreated)
107-
render.JSON(rw, r, convertProjectHistory(history))
160+
render.JSON(rw, r, convertProjectHistory(projectHistory, provisionerJob))
108161
}
109162

110-
func convertProjectHistory(history database.ProjectHistory) ProjectHistory {
163+
func convertProjectHistory(history database.ProjectHistory, job database.ProvisionerJob) ProjectHistory {
111164
return ProjectHistory{
112165
ID: history.ID,
113166
ProjectID: history.ProjectID,
114167
CreatedAt: history.CreatedAt,
115168
UpdatedAt: history.UpdatedAt,
116169
Name: history.Name,
170+
Import: convertProvisionerJob(job),
117171
}
118172
}
173+
174+
func projectHistoryLogsChannel(projectHistoryID uuid.UUID) string {
175+
return fmt.Sprintf("project-history-logs:%s", projectHistoryID)
176+
}

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