@@ -13,6 +13,7 @@ import (
13
13
"strings"
14
14
15
15
"github.com/hashicorp/terraform-exec/tfexec"
16
+ tfjson "github.com/hashicorp/terraform-json"
16
17
"github.com/mitchellh/mapstructure"
17
18
"golang.org/x/xerrors"
18
19
@@ -75,10 +76,13 @@ func (t *terraform) Provision(request *proto.Provision_Request, stream proto.DRP
75
76
}
76
77
77
78
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 ]
81
83
}
84
+ env ["CODER_URL" ] = request .Metadata .CoderUrl
85
+ env ["CODER_WORKSPACE_TRANSITION" ] = strings .ToLower (request .Metadata .WorkspaceTransition .String ())
82
86
planfilePath := filepath .Join (request .Directory , "terraform.tfplan" )
83
87
options := []tfexec.PlanOption {tfexec .JSON (true ), tfexec .Out (planfilePath )}
84
88
for _ , param := range request .ParameterValues {
@@ -159,9 +163,31 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
159
163
_ = reader .Close ()
160
164
<- closeChan
161
165
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
+
162
189
resources := make ([]* proto.Resource , 0 )
163
190
agents := map [string ]* proto.Agent {}
164
- agentDepends := map [string ][]string {}
165
191
166
192
// Store all agents inside the maps!
167
193
for _ , resource := range plan .Config .RootModule .Resources {
@@ -196,9 +222,10 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
196
222
}
197
223
switch authTypeValue {
198
224
case "google-instance-identity" :
225
+ instanceID , _ := block ["instance_id" ].ConstantValue .(string )
199
226
agent .Auth = & proto.Agent_GoogleInstanceIdentity {
200
227
GoogleInstanceIdentity : & proto.GoogleInstanceIdentityAuth {
201
- InstanceId : block [ "instance_id" ]. ConstantValue .( string ) ,
228
+ InstanceId : instanceID ,
202
229
},
203
230
}
204
231
default :
@@ -208,31 +235,33 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
208
235
}
209
236
}
210
237
211
- resourceKey := strings .Join ([]string {resource .Type , resource .Name }, "." )
212
- agents [resourceKey ] = agent
213
- agentDepends [resourceKey ] = resource .DependsOn
238
+ agents [resource .Address ] = agent
214
239
}
215
240
216
- for _ , resource := range plan .Config .RootModule .Resources {
241
+ for _ , resource := range plan .PlannedValues .RootModule .Resources {
217
242
if resource .Type == "coder_agent" {
218
243
continue
219
244
}
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 )
220
249
var agent * proto.Agent
221
250
// Associate resources that depend on an agent.
222
- for _ , dep := range resource . DependsOn {
251
+ for _ , dependency := range resourceDependencies [ resourceAddress ] {
223
252
var has bool
224
- agent , has = agents [dep ]
253
+ agent , has = agents [dependency ]
225
254
if has {
226
255
break
227
256
}
228
257
}
229
258
// Associate resources where the agent depends on it.
230
- for agentKey , dependsOn := range agentDepends {
231
- for _ , depend := range dependsOn {
232
- if depend != strings . Join ([] string { resource . Type , resource . Name }, "." ) {
259
+ for agentAddress := range agents {
260
+ for _ , depend := range resourceDependencies [ agentAddress ] {
261
+ if depend != resourceAddress {
233
262
continue
234
263
}
235
- agent = agents [agentKey ]
264
+ agent = agents [agentAddress ]
236
265
break
237
266
}
238
267
}
@@ -254,10 +283,11 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr
254
283
}
255
284
256
285
func (t * terraform ) runTerraformApply (ctx context.Context , terraform * tfexec.Terraform , request * proto.Provision_Request , stream proto.DRPCProvisioner_ProvisionStream , statefilePath string ) error {
257
- env := []string {
258
- "CODER_URL=" + request .Metadata .CoderUrl ,
259
- "CODER_WORKSPACE_TRANSITION=" + strings .ToLower (request .Metadata .WorkspaceTransition .String ()),
260
- }
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
+ )
261
291
vars := []string {}
262
292
for _ , param := range request .ParameterValues {
263
293
switch param .DestinationScheme {
0 commit comments