6
6
"context"
7
7
"encoding/json"
8
8
"fmt"
9
+ "github.com/coder/terraform-provider-coder/provider"
9
10
"io"
10
11
"os"
11
12
"os/exec"
@@ -261,6 +262,16 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
261
262
e .mut .Lock ()
262
263
defer e .mut .Unlock ()
263
264
265
+ var isPrebuild bool
266
+ for _ , v := range env {
267
+ if envName (v ) == provider .IsPrebuildEnvironmentVariable () && envVar (v ) == "true" {
268
+ isPrebuild = true
269
+ break
270
+ }
271
+ }
272
+
273
+ _ = isPrebuild
274
+
264
275
planfilePath := getPlanFilePath (e .workdir )
265
276
args := []string {
266
277
"plan" ,
@@ -329,6 +340,68 @@ func onlyDataResources(sm tfjson.StateModule) tfjson.StateModule {
329
340
return filtered
330
341
}
331
342
343
+ func (e * executor ) logResourceReplacements (ctx context.Context , plan * tfjson.Plan ) {
344
+ if plan == nil {
345
+ return
346
+ }
347
+
348
+ if len (plan .ResourceChanges ) == 0 {
349
+ return
350
+ }
351
+ var (
352
+ count int
353
+ replacements = make (map [string ][]string , len (plan .ResourceChanges ))
354
+ )
355
+
356
+ for _ , ch := range plan .ResourceChanges {
357
+ // No change, no problem!
358
+ if ch .Change == nil {
359
+ continue
360
+ }
361
+
362
+ // No-op change, no problem!
363
+ if ch .Change .Actions .NoOp () {
364
+ continue
365
+ }
366
+
367
+ // No replacements, no problem!
368
+ if len (ch .Change .ReplacePaths ) == 0 {
369
+ continue
370
+ }
371
+
372
+ // Replacing our resources, no problem!
373
+ if strings .Index (ch .Type , "coder_" ) == 0 {
374
+ continue
375
+ }
376
+
377
+ for _ , p := range ch .Change .ReplacePaths {
378
+ var path string
379
+ switch p .(type ) {
380
+ case []interface {}:
381
+ segs := p .([]interface {})
382
+ list := make ([]string , 0 , len (segs ))
383
+ for _ , s := range segs {
384
+ list = append (list , fmt .Sprintf ("%v" , s ))
385
+ }
386
+ path = strings .Join (list , "." )
387
+ default :
388
+ path = fmt .Sprintf ("%v" , p )
389
+ }
390
+
391
+ replacements [ch .Address ] = append (replacements [ch .Address ], path )
392
+ }
393
+
394
+ count ++
395
+ }
396
+
397
+ if count > 0 {
398
+ e .server .logger .Warn (ctx , "plan introduces resource changes" , slog .F ("count" , count ))
399
+ for n , p := range replacements {
400
+ e .server .logger .Warn (ctx , "resource will be replaced!" , slog .F ("name" , n ), slog .F ("replacement_paths" , strings .Join (p , "," )))
401
+ }
402
+ }
403
+ }
404
+
332
405
// planResources must only be called while the lock is held.
333
406
func (e * executor ) planResources (ctx , killCtx context.Context , planfilePath string ) (* State , error ) {
334
407
ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
@@ -339,6 +412,8 @@ func (e *executor) planResources(ctx, killCtx context.Context, planfilePath stri
339
412
return nil , xerrors .Errorf ("show terraform plan file: %w" , err )
340
413
}
341
414
415
+ e .logResourceReplacements (ctx , plan )
416
+
342
417
rawGraph , err := e .graph (ctx , killCtx )
343
418
if err != nil {
344
419
return nil , xerrors .Errorf ("graph: %w" , err )
0 commit comments