Skip to content

Commit 3f99334

Browse files
committed
Fix plan resource parsing
1 parent 0d3de18 commit 3f99334

File tree

7 files changed

+84
-33
lines changed

7 files changed

+84
-33
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"stretchr",
6363
"tcpip",
6464
"tfexec",
65+
"tfjson",
6566
"tfstate",
6667
"unconvert",
6768
"webrtc",

cli/projectcreate.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ func projectCreate() *cobra.Command {
7171
if err != nil {
7272
return err
7373
}
74-
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
75-
Name: name,
76-
VersionImportJobID: job.ID,
77-
})
78-
if err != nil {
79-
return err
80-
}
8174

8275
_, err = prompt(cmd, &promptui.Prompt{
8376
Label: "Create project?",
@@ -91,6 +84,14 @@ func projectCreate() *cobra.Command {
9184
return err
9285
}
9386

87+
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
88+
Name: name,
89+
VersionImportJobID: job.ID,
90+
})
91+
if err != nil {
92+
return err
93+
}
94+
9495
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s The %s project has been created!\n", caret, color.HiCyanString(project.Name))
9596
_, err = prompt(cmd, &promptui.Prompt{
9697
Label: "Create a new workspace?",

cli/projects.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.Para
7878
if resource.Transition == database.WorkspaceTransitionStop {
7979
transition = color.HiRedString("stop")
8080
}
81+
if resource.AgentID != nil {
82+
transition += " with agent"
83+
}
8184
_, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s %s on %s\n\n", color.HiCyanString(resource.Type), color.HiCyanString(resource.Name), transition)
8285
}
8386
return nil

coderd/projectimport.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re
177177
if resources == nil {
178178
resources = []database.ProvisionerJobResource{}
179179
}
180+
apiResources := make([]ProvisionerJobResource, 0)
181+
for _, resource := range resources {
182+
apiResources = append(apiResources, convertProvisionerJobResource(resource))
183+
}
180184
render.Status(r, http.StatusOK)
181-
render.JSON(rw, r, resources)
185+
render.JSON(rw, r, apiResources)
182186
}

coderd/provisionerjobs.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ type ProvisionerJobResource struct {
6161
ID uuid.UUID `json:"id"`
6262
CreatedAt time.Time `json:"created_at"`
6363
JobID uuid.UUID `json:"job_id"`
64-
Transition database.WorkspaceTransition `json:"workspace_transition"`
64+
Transition database.WorkspaceTransition `json:"transition"`
6565
Type string `json:"type"`
6666
Name string `json:"name"`
67+
AgentID *uuid.UUID `json:"agent_id,omitempty"`
6768
}
6869

6970
type ProvisionerJobAgent struct {
@@ -291,6 +292,21 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJo
291292
return job
292293
}
293294

295+
func convertProvisionerJobResource(resource database.ProvisionerJobResource) ProvisionerJobResource {
296+
apiResource := ProvisionerJobResource{
297+
ID: resource.ID,
298+
CreatedAt: resource.CreatedAt,
299+
JobID: resource.JobID,
300+
Transition: resource.Transition,
301+
Type: resource.Type,
302+
Name: resource.Name,
303+
}
304+
if resource.AgentID.Valid {
305+
apiResource.AgentID = &resource.AgentID.UUID
306+
}
307+
return apiResource
308+
}
309+
294310
func provisionerJobLogsChannel(jobID uuid.UUID) string {
295311
return fmt.Sprintf("provisioner-log-logs:%s", jobID)
296312
}

provisioner/terraform/provision.go

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414

1515
"github.com/hashicorp/terraform-exec/tfexec"
16+
tfjson "github.com/hashicorp/terraform-json"
1617
"github.com/mitchellh/mapstructure"
1718
"golang.org/x/xerrors"
1819

@@ -75,10 +76,13 @@ func (t *terraform) Provision(request *proto.Provision_Request, stream proto.DRP
7576
}
7677

7778
func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream) error {
78-
env := map[string]string{
79-
"CODER_URL": request.Metadata.CoderUrl,
80-
"CODER_WORKSPACE_TRANSITION": strings.ToLower(request.Metadata.WorkspaceTransition.String()),
79+
env := map[string]string{}
80+
for _, envEntry := range os.Environ() {
81+
parts := strings.SplitN(envEntry, "=", 2)
82+
env[parts[0]] = parts[1]
8183
}
84+
env["CODER_URL"] = request.Metadata.CoderUrl
85+
env["CODER_WORKSPACE_TRANSITION"] = strings.ToLower(request.Metadata.WorkspaceTransition.String())
8286
planfilePath := filepath.Join(request.Directory, "terraform.tfplan")
8387
options := []tfexec.PlanOption{tfexec.JSON(true), tfexec.Out(planfilePath)}
8488
for _, param := range request.ParameterValues {
@@ -159,9 +163,31 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
159163
_ = reader.Close()
160164
<-closeChan
161165

166+
// Maps resource dependencies to expression references.
167+
// This is *required* for a plan, because "DependsOn"
168+
// does not propagate.
169+
resourceDependencies := map[string][]string{}
170+
for _, resource := range plan.Config.RootModule.Resources {
171+
if resource.Expressions == nil {
172+
resource.Expressions = map[string]*tfjson.Expression{}
173+
}
174+
// Count expression is separated for logical reasons,
175+
// but it's simpler syntactically for us to combine here.
176+
if resource.CountExpression != nil {
177+
resource.Expressions["count"] = resource.CountExpression
178+
}
179+
for _, expression := range resource.Expressions {
180+
dependencies, exists := resourceDependencies[resource.Address]
181+
if !exists {
182+
dependencies = []string{}
183+
}
184+
dependencies = append(dependencies, expression.References...)
185+
resourceDependencies[resource.Address] = dependencies
186+
}
187+
}
188+
162189
resources := make([]*proto.Resource, 0)
163190
agents := map[string]*proto.Agent{}
164-
agentDepends := map[string][]string{}
165191

166192
// Store all agents inside the maps!
167193
for _, resource := range plan.Config.RootModule.Resources {
@@ -209,31 +235,33 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
209235
}
210236
}
211237

212-
resourceKey := strings.Join([]string{resource.Type, resource.Name}, ".")
213-
agents[resourceKey] = agent
214-
agentDepends[resourceKey] = resource.DependsOn
238+
agents[resource.Address] = agent
215239
}
216240

217-
for _, resource := range plan.Config.RootModule.Resources {
241+
for _, resource := range plan.PlannedValues.RootModule.Resources {
218242
if resource.Type == "coder_agent" {
219243
continue
220244
}
245+
// The resource address on planned values can include the indexed
246+
// value like "[0]", but the config doesn't have these, and we don't
247+
// care which index the resource is.
248+
resourceAddress := fmt.Sprintf("%s.%s", resource.Type, resource.Name)
221249
var agent *proto.Agent
222250
// Associate resources that depend on an agent.
223-
for _, dep := range resource.DependsOn {
251+
for _, dependency := range resourceDependencies[resourceAddress] {
224252
var has bool
225-
agent, has = agents[dep]
253+
agent, has = agents[dependency]
226254
if has {
227255
break
228256
}
229257
}
230258
// Associate resources where the agent depends on it.
231-
for agentKey, dependsOn := range agentDepends {
232-
for _, depend := range dependsOn {
233-
if depend != strings.Join([]string{resource.Type, resource.Name}, ".") {
259+
for agentAddress := range agents {
260+
for _, depend := range resourceDependencies[agentAddress] {
261+
if depend != resource.Address {
234262
continue
235263
}
236-
agent = agents[agentKey]
264+
agent = agents[agentAddress]
237265
break
238266
}
239267
}
@@ -255,10 +283,11 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
255283
}
256284

257285
func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream, statefilePath string) error {
258-
env := []string{
259-
"CODER_URL=" + request.Metadata.CoderUrl,
260-
"CODER_WORKSPACE_TRANSITION=" + strings.ToLower(request.Metadata.WorkspaceTransition.String()),
261-
}
286+
env := os.Environ()
287+
env = append(env,
288+
"CODER_URL="+request.Metadata.CoderUrl,
289+
"CODER_WORKSPACE_TRANSITION="+strings.ToLower(request.Metadata.WorkspaceTransition.String()),
290+
)
262291
vars := []string{}
263292
for _, param := range request.ParameterValues {
264293
switch param.DestinationScheme {

provisioner/terraform/provision_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,10 @@ provider "coder" {
235235
Files: map[string]string{
236236
"main.tf": provider + `
237237
resource "coder_agent" "A" {
238+
count = 1
238239
}
239240
resource "null_resource" "A" {
240-
depends_on = [
241-
coder_agent.A
242-
]
241+
count = length(coder_agent.A)
243242
}`,
244243
},
245244
Request: &proto.Provision_Request{
@@ -266,9 +265,7 @@ provider "coder" {
266265
Files: map[string]string{
267266
"main.tf": provider + `
268267
resource "coder_agent" "A" {
269-
depends_on = [
270-
null_resource.A
271-
]
268+
count = length(null_resource.A)
272269
auth {
273270
type = "google-instance-identity"
274271
instance_id = "an-instance"

0 commit comments

Comments
 (0)