Skip to content

Commit 79a56b6

Browse files
committed
Basic creation flow works!
1 parent 8fe05d6 commit 79a56b6

13 files changed

+377
-260
lines changed

cli/projectcreate.go

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import (
1111

1212
"github.com/briandowns/spinner"
1313
"github.com/fatih/color"
14+
"github.com/google/uuid"
1415
"github.com/manifoldco/promptui"
1516
"github.com/spf13/cobra"
1617
"golang.org/x/xerrors"
1718

1819
"github.com/coder/coder/coderd"
1920
"github.com/coder/coder/codersdk"
2021
"github.com/coder/coder/database"
22+
"github.com/coder/coder/provisionerd"
2123
)
2224

2325
func projectCreate() *cobra.Command {
@@ -49,8 +51,8 @@ func projectCreate() *cobra.Command {
4951
Default: filepath.Base(directory),
5052
Label: "What's your project's name?",
5153
Validate: func(s string) error {
52-
_, err = client.Project(cmd.Context(), organization.Name, s)
53-
if err == nil {
54+
project, _ := client.Project(cmd.Context(), organization.Name, s)
55+
if project.ID.String() != uuid.Nil.String() {
5456
return xerrors.New("A project already exists with that name!")
5557
}
5658
return nil
@@ -63,6 +65,7 @@ func projectCreate() *cobra.Command {
6365
spin := spinner.New(spinner.CharSets[0], 25*time.Millisecond)
6466
spin.Suffix = " Uploading current directory..."
6567
spin.Start()
68+
6669
defer spin.Stop()
6770

6871
bytes, err := tarDirectory(directory)
@@ -79,14 +82,6 @@ func projectCreate() *cobra.Command {
7982
StorageMethod: database.ProvisionerStorageMethodFile,
8083
StorageSource: resp.Hash,
8184
Provisioner: database.ProvisionerTypeTerraform,
82-
// SkipResources on first import to detect variables defined by the project.
83-
SkipResources: true,
84-
// ParameterValues: []coderd.CreateParameterValueRequest{{
85-
// Name: "aws_access_key",
86-
// SourceValue: "tomato",
87-
// SourceScheme: database.ParameterSourceSchemeData,
88-
// DestinationScheme: database.ParameterDestinationSchemeProvisionerVariable,
89-
// }},
9085
})
9186
if err != nil {
9287
return err
@@ -102,33 +97,60 @@ func projectCreate() *cobra.Command {
10297
if !ok {
10398
break
10499
}
105-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[parse]"), log.Output)
100+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[tf]"), log.Output)
106101
}
107102

108-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Parsed project source... displaying parameters:")
109-
110-
schemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
103+
job, err = client.ProvisionerJob(cmd.Context(), organization.Name, job.ID)
111104
if err != nil {
112105
return err
113106
}
114107

115-
values, err := client.ProvisionerJobParameterValues(cmd.Context(), organization.Name, job.ID)
108+
if provisionerd.IsMissingParameterError(job.Error) {
109+
fmt.Printf("Missing something!\n")
110+
return nil
111+
}
112+
113+
resources, err := client.ProvisionerJobResources(cmd.Context(), organization.Name, job.ID)
116114
if err != nil {
117115
return err
118116
}
119-
valueBySchemaID := map[string]coderd.ComputedParameterValue{}
120-
for _, value := range values {
121-
valueBySchemaID[value.SchemaID.String()] = value
122-
}
123117

124-
for _, schema := range schemas {
125-
if value, ok := valueBySchemaID[schema.ID.String()]; ok {
126-
fmt.Printf("Value for: %s %s\n", value.Name, value.SourceValue)
127-
continue
128-
}
129-
fmt.Printf("No value for: %s\n", schema.Name)
118+
fmt.Printf("Resources: %+v\n", resources)
119+
120+
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
121+
Name: name,
122+
VersionImportJobID: job.ID,
123+
})
124+
if err != nil {
125+
return err
130126
}
131127

128+
fmt.Printf("Project: %+v\n", project)
129+
130+
// _, _ = fmt.Fprintf(cmd.OutOrStdout(), "Parsed project source... displaying parameters:")
131+
132+
// schemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
133+
// if err != nil {
134+
// return err
135+
// }
136+
137+
// values, err := client.ProvisionerJobParameterValues(cmd.Context(), organization.Name, job.ID)
138+
// if err != nil {
139+
// return err
140+
// }
141+
// valueBySchemaID := map[string]coderd.ComputedParameterValue{}
142+
// for _, value := range values {
143+
// valueBySchemaID[value.SchemaID.String()] = value
144+
// }
145+
146+
// for _, schema := range schemas {
147+
// if value, ok := valueBySchemaID[schema.ID.String()]; ok {
148+
// fmt.Printf("Value for: %s %s\n", value.Name, value.SourceValue)
149+
// continue
150+
// }
151+
// fmt.Printf("No value for: %s\n", schema.Name)
152+
// }
153+
132154
// schemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
133155
// if err != nil {
134156
// return err

cli/root.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ func runPrompt(cmd *cobra.Command, prompt *promptui.Prompt) (string, error) {
161161
Invalid: invalid,
162162
Valid: valid,
163163
}
164+
oldValidate := prompt.Validate
165+
if oldValidate != nil {
166+
// Override the validate function to pass our default!
167+
prompt.Validate = func(s string) error {
168+
if s == "" {
169+
s = defaultValue
170+
}
171+
return oldValidate(s)
172+
}
173+
}
164174
value, err := prompt.Run()
165175
if value == "" && !prompt.IsConfirm {
166176
value = defaultValue

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func New(options *Options) http.Handler {
123123
r.Get("/", api.provisionerJobByOrganization)
124124
r.Get("/schemas", api.provisionerJobParameterSchemasByID)
125125
r.Get("/computed", api.provisionerJobComputedParametersByID)
126+
r.Get("/resources", api.provisionerJobResourcesByID)
126127
r.Get("/logs", api.provisionerJobLogsByID)
127128
})
128129
})

coderd/provisionerdaemons.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,30 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
437437

438438
switch jobType := completed.Type.(type) {
439439
case *proto.CompletedJob_ProjectImport_:
440+
for transition, resources := range map[database.WorkspaceTransition][]*sdkproto.Resource{
441+
database.WorkspaceTransitionStart: jobType.ProjectImport.StartResources,
442+
database.WorkspaceTransitionStop: jobType.ProjectImport.StopResources,
443+
} {
444+
for _, resource := range resources {
445+
server.Logger.Info(ctx, "inserting project import job resource",
446+
slog.F("job_id", job.ID.String()),
447+
slog.F("resource_name", resource.Name),
448+
slog.F("resource_type", resource.Type),
449+
slog.F("transition", transition))
450+
_, err = server.Database.InsertProjectImportJobResource(ctx, database.InsertProjectImportJobResourceParams{
451+
ID: uuid.New(),
452+
CreatedAt: database.Now(),
453+
JobID: jobID,
454+
Transition: transition,
455+
Type: resource.Type,
456+
Name: resource.Name,
457+
})
458+
if err != nil {
459+
return nil, xerrors.Errorf("insert resource: %w", err)
460+
}
461+
}
462+
}
463+
440464
err = server.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
441465
ID: jobID,
442466
UpdatedAt: database.Now(),

coderd/provisionerjobs.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"github.com/coder/coder/httpmw"
1717
)
1818

19+
type ProjectImportJobResource database.ProjectImportJobResource
20+
1921
type ProvisionerJobStatus string
2022

2123
// Completed returns whether the job is still processing.
@@ -125,9 +127,9 @@ func (api *api) postProvisionerImportJobByOrganization(rw http.ResponseWriter, r
125127
// Return parsed parameter schemas for a job.
126128
func (api *api) provisionerJobParameterSchemasByID(rw http.ResponseWriter, r *http.Request) {
127129
job := httpmw.ProvisionerJobParam(r)
128-
if convertProvisionerJob(job).Status != ProvisionerJobStatusSucceeded {
130+
if !convertProvisionerJob(job).Status.Completed() {
129131
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
130-
Message: fmt.Sprintf("Job is in state %q! Must be %q.", convertProvisionerJob(job).Status, ProvisionerJobStatusSucceeded),
132+
Message: "Job hasn't completed!",
131133
})
132134
return
133135
}
@@ -150,9 +152,9 @@ func (api *api) provisionerJobParameterSchemasByID(rw http.ResponseWriter, r *ht
150152
func (api *api) provisionerJobComputedParametersByID(rw http.ResponseWriter, r *http.Request) {
151153
apiKey := httpmw.APIKey(r)
152154
job := httpmw.ProvisionerJobParam(r)
153-
if convertProvisionerJob(job).Status != ProvisionerJobStatusSucceeded {
155+
if !convertProvisionerJob(job).Status.Completed() {
154156
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
155-
Message: fmt.Sprintf("Job is in state %q! Must be %q.", convertProvisionerJob(job).Status, ProvisionerJobStatusSucceeded),
157+
Message: "Job hasn't completed!",
156158
})
157159
return
158160
}
@@ -163,6 +165,29 @@ func (api *api) provisionerJobComputedParametersByID(rw http.ResponseWriter, r *
163165
})
164166
}
165167

168+
func (api *api) provisionerJobResourcesByID(rw http.ResponseWriter, r *http.Request) {
169+
job := httpmw.ProvisionerJobParam(r)
170+
if !convertProvisionerJob(job).Status.Completed() {
171+
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
172+
Message: "Job hasn't completed!",
173+
})
174+
return
175+
}
176+
resources, err := api.Database.GetProjectImportJobResourcesByJobID(r.Context(), job.ID)
177+
if errors.Is(err, sql.ErrNoRows) {
178+
err = nil
179+
}
180+
if err != nil {
181+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
182+
Message: fmt.Sprintf("get project import job resources: %s", err),
183+
})
184+
return
185+
}
186+
187+
render.Status(r, http.StatusOK)
188+
render.JSON(rw, r, resources)
189+
}
190+
166191
func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJob {
167192
job := ProvisionerJob{
168193
ID: provisionerJob.ID,

coderd/provisionerjobs_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/coder/coder/coderd"
1212
"github.com/coder/coder/coderd/coderdtest"
13+
"github.com/coder/coder/coderd/parameter"
1314
"github.com/coder/coder/codersdk"
1415
"github.com/coder/coder/database"
1516
"github.com/coder/coder/provisioner/echo"
@@ -170,3 +171,39 @@ func TestProvisionerJobParametersByID(t *testing.T) {
170171
require.Equal(t, params[0].SourceValue, "")
171172
})
172173
}
174+
175+
func TestProvisionerJobResourcesByID(t *testing.T) {
176+
t.Parallel()
177+
t.Run("Something", func(t *testing.T) {
178+
t.Parallel()
179+
client := coderdtest.New(t)
180+
user := coderdtest.CreateInitialUser(t, client)
181+
_ = coderdtest.NewProvisionerDaemon(t, client)
182+
job := coderdtest.CreateProjectImportProvisionerJob(t, client, user.Organization, &echo.Responses{
183+
Parse: []*proto.Parse_Response{{
184+
Type: &proto.Parse_Response_Complete{
185+
Complete: &proto.Parse_Complete{
186+
ParameterSchemas: []*proto.ParameterSchema{{
187+
Name: parameter.CoderWorkspaceTransition,
188+
}},
189+
},
190+
},
191+
}},
192+
Provision: []*proto.Provision_Response{{
193+
Type: &proto.Provision_Response_Complete{
194+
Complete: &proto.Provision_Complete{
195+
Resources: []*proto.Resource{{
196+
Name: "hello",
197+
Type: "ec2_instance",
198+
}},
199+
},
200+
},
201+
}},
202+
})
203+
coderdtest.AwaitProvisionerJob(t, client, user.Organization, job.ID)
204+
resources, err := client.ProvisionerJobResources(context.Background(), user.Organization, job.ID)
205+
require.NoError(t, err)
206+
// One for start, and one for stop!
207+
require.Len(t, resources, 2)
208+
})
209+
}

codersdk/provisioners.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,16 @@ func (c *Client) ProvisionerJobParameterValues(ctx context.Context, organization
179179
var params []coderd.ComputedParameterValue
180180
return params, json.NewDecoder(res.Body).Decode(&params)
181181
}
182+
183+
func (c *Client) ProvisionerJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProjectImportJobResource, error) {
184+
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/provisioners/jobs/%s/%s/resources", organization, job), nil)
185+
if err != nil {
186+
return nil, err
187+
}
188+
defer res.Body.Close()
189+
if res.StatusCode != http.StatusOK {
190+
return nil, readBodyAsError(res)
191+
}
192+
var resources []coderd.ProjectImportJobResource
193+
return resources, json.NewDecoder(res.Body).Decode(&resources)
194+
}

database/databasefake/databasefake.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,23 @@ func (q *fakeQuerier) GetProjectByOrganizationAndName(_ context.Context, arg dat
401401
return database.Project{}, sql.ErrNoRows
402402
}
403403

404+
func (q *fakeQuerier) GetProjectImportJobResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]database.ProjectImportJobResource, error) {
405+
q.mutex.Lock()
406+
defer q.mutex.Unlock()
407+
408+
resources := make([]database.ProjectImportJobResource, 0)
409+
for _, resource := range q.projectImportJobResource {
410+
if resource.JobID.String() != jobID.String() {
411+
continue
412+
}
413+
resources = append(resources, resource)
414+
}
415+
if len(resources) == 0 {
416+
return nil, sql.ErrNoRows
417+
}
418+
return resources, nil
419+
}
420+
404421
func (q *fakeQuerier) GetProjectVersionsByProjectID(_ context.Context, projectID uuid.UUID) ([]database.ProjectVersion, error) {
405422
q.mutex.Lock()
406423
defer q.mutex.Unlock()

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.

database/query.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ FROM
173173
WHERE
174174
job_id = $1;
175175

176+
-- name: GetProjectImportJobResourcesByJobID :many
177+
SELECT
178+
*
179+
FROM
180+
project_import_job_resource
181+
WHERE
182+
job_id = $1;
183+
176184
-- name: GetProjectVersionsByProjectID :many
177185
SELECT
178186
*

0 commit comments

Comments
 (0)