@@ -261,17 +261,6 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
261261 e .mut .Lock ()
262262 defer e .mut .Unlock ()
263263
264- // TODO: defunct?
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-
275264 planfilePath := getPlanFilePath (e .workdir )
276265 args := []string {
277266 "plan" ,
@@ -341,6 +330,68 @@ func onlyDataResources(sm tfjson.StateModule) tfjson.StateModule {
341330 return filtered
342331}
343332
333+ func (e * executor ) logResourceReplacements (ctx context.Context , plan * tfjson.Plan ) {
334+ if plan == nil {
335+ return
336+ }
337+
338+ if len (plan .ResourceChanges ) == 0 {
339+ return
340+ }
341+ var (
342+ count int
343+ replacements = make (map [string ][]string , len (plan .ResourceChanges ))
344+ )
345+
346+ for _ , ch := range plan .ResourceChanges {
347+ // No change, no problem!
348+ if ch .Change == nil {
349+ continue
350+ }
351+
352+ // No-op change, no problem!
353+ if ch .Change .Actions .NoOp () {
354+ continue
355+ }
356+
357+ // No replacements, no problem!
358+ if len (ch .Change .ReplacePaths ) == 0 {
359+ continue
360+ }
361+
362+ // Replacing our resources, no problem!
363+ if strings .Index (ch .Type , "coder_" ) == 0 {
364+ continue
365+ }
366+
367+ for _ , p := range ch .Change .ReplacePaths {
368+ var path string
369+ switch p := p .(type ) {
370+ case []interface {}:
371+ segs := p
372+ list := make ([]string , 0 , len (segs ))
373+ for _ , s := range segs {
374+ list = append (list , fmt .Sprintf ("%v" , s ))
375+ }
376+ path = strings .Join (list , "." )
377+ default :
378+ path = fmt .Sprintf ("%v" , p )
379+ }
380+
381+ replacements [ch .Address ] = append (replacements [ch .Address ], path )
382+ }
383+
384+ count ++
385+ }
386+
387+ if count > 0 {
388+ e .server .logger .Warn (ctx , "plan introduces resource changes" , slog .F ("count" , count ))
389+ for n , p := range replacements {
390+ e .server .logger .Warn (ctx , "resource will be replaced!" , slog .F ("name" , n ), slog .F ("replacement_paths" , strings .Join (p , "," )))
391+ }
392+ }
393+ }
394+
344395// planResources must only be called while the lock is held.
345396func (e * executor ) planResources (ctx , killCtx context.Context , planfilePath string ) (* State , json.RawMessage , error ) {
346397 ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
@@ -351,6 +402,8 @@ func (e *executor) planResources(ctx, killCtx context.Context, planfilePath stri
351402 return nil , nil , xerrors .Errorf ("show terraform plan file: %w" , err )
352403 }
353404
405+ e .logResourceReplacements (ctx , plan )
406+
354407 rawGraph , err := e .graph (ctx , killCtx )
355408 if err != nil {
356409 return nil , nil , xerrors .Errorf ("graph: %w" , err )
0 commit comments