@@ -23,7 +23,6 @@ import (
2323 "cdr.dev/slog"
2424 "github.com/coder/coder/v2/provisionersdk/tfpath"
2525
26- "github.com/coder/coder/v2/coderd/database"
2726 "github.com/coder/coder/v2/coderd/tracing"
2827 "github.com/coder/coder/v2/provisionersdk/proto"
2928)
@@ -283,7 +282,7 @@ func (e *executor) init(ctx, killCtx context.Context, logr logSink) error {
283282func checksumFileCRC32 (ctx context.Context , logger slog.Logger , path string ) uint32 {
284283 content , err := os .ReadFile (path )
285284 if err != nil {
286- logger .Debug (ctx , "file %s does not exist or can't be read, skip checksum calculation" )
285+ logger .Debug (ctx , fmt . Sprintf ( "file %s does not exist or can't be read, skip checksum calculation" , path ) )
287286 return 0
288287 }
289288 return crc32 .ChecksumIEEE (content )
@@ -330,34 +329,16 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
330329 return nil , xerrors .Errorf ("terraform plan: %w" , err )
331330 }
332331
333- // Capture the duration of the call to `terraform graph`.
334- graphTimings := newTimingAggregator (database .ProvisionerJobTimingStageGraph )
335- graphTimings .ingest (createGraphTimingsEvent (timingGraphStart ))
336-
337- state , plan , err := e .planResources (ctx , killCtx , planfilePath )
332+ plan , err := e .parsePlan (ctx , killCtx , planfilePath )
338333 if err != nil {
339- graphTimings .ingest (createGraphTimingsEvent (timingGraphErrored ))
340- return nil , xerrors .Errorf ("plan resources: %w" , err )
334+ return nil , xerrors .Errorf ("show terraform plan file: %w" , err )
341335 }
336+
342337 planJSON , err := json .Marshal (plan )
343338 if err != nil {
344339 return nil , xerrors .Errorf ("marshal plan: %w" , err )
345340 }
346341
347- graphTimings .ingest (createGraphTimingsEvent (timingGraphComplete ))
348-
349- var moduleFiles []byte
350- // Skipping modules archiving is useful if the caller does not need it, eg during
351- // a workspace build. This removes some added costs of sending the modules
352- // payload back to coderd if coderd is just going to ignore it.
353- if ! req .OmitModuleFiles {
354- moduleFiles , err = GetModulesArchive (os .DirFS (e .files .WorkDirectory ()))
355- if err != nil {
356- // TODO: we probably want to persist this error or make it louder eventually
357- e .logger .Warn (ctx , "failed to archive terraform modules" , slog .Error (err ))
358- }
359- }
360-
361342 // When a prebuild claim attempt is made, log a warning if a resource is due to be replaced, since this will obviate
362343 // the point of prebuilding if the expensive resource is replaced once claimed!
363344 var (
@@ -384,18 +365,18 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
384365 }
385366 }
386367
368+ state , err := ConvertPlanState (plan )
369+ if err != nil {
370+ return nil , xerrors .Errorf ("convert plan state: %w" , err )
371+ }
372+
373+ // DoneOut must be completed before we aggregate timings to ensure all logs have been processed.
374+ <- doneOut
387375 msg := & proto.PlanComplete {
388- Parameters : state .Parameters ,
389- Resources : state .Resources ,
390- ExternalAuthProviders : state .ExternalAuthProviders ,
391- Timings : graphTimings .aggregate (),
392- Presets : state .Presets ,
393- Plan : planJSON ,
394- ResourceReplacements : resReps ,
395- ModuleFiles : moduleFiles ,
396- HasAiTasks : state .HasAITasks ,
397- AiTasks : state .AITasks ,
398- HasExternalAgents : state .HasExternalAgents ,
376+ Plan : planJSON ,
377+ DailyCost : state .DailyCost ,
378+ ResourceReplacements : resReps ,
379+ AiTaskCount : state .AITaskCount ,
399380 }
400381
401382 return msg , nil
@@ -418,42 +399,6 @@ func onlyDataResources(sm tfjson.StateModule) tfjson.StateModule {
418399 return filtered
419400}
420401
421- // planResources must only be called while the lock is held.
422- func (e * executor ) planResources (ctx , killCtx context.Context , planfilePath string ) (* State , * tfjson.Plan , error ) {
423- ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
424- defer span .End ()
425-
426- plan , err := e .parsePlan (ctx , killCtx , planfilePath )
427- if err != nil {
428- return nil , nil , xerrors .Errorf ("show terraform plan file: %w" , err )
429- }
430-
431- rawGraph , err := e .graph (ctx , killCtx )
432- if err != nil {
433- return nil , nil , xerrors .Errorf ("graph: %w" , err )
434- }
435- modules := []* tfjson.StateModule {}
436- if plan .PriorState != nil {
437- // We need the data resources for rich parameters. For some reason, they
438- // only show up in the PriorState.
439- //
440- // We don't want all prior resources, because Quotas (and
441- // future features) would never know which resources are getting
442- // deleted by a stop.
443-
444- filtered := onlyDataResources (* plan .PriorState .Values .RootModule )
445- modules = append (modules , & filtered )
446- }
447- modules = append (modules , plan .PlannedValues .RootModule )
448-
449- state , err := ConvertState (ctx , modules , rawGraph , e .server .logger )
450- if err != nil {
451- return nil , nil , err
452- }
453-
454- return state , plan , nil
455- }
456-
457402// parsePlan must only be called while the lock is held.
458403func (e * executor ) parsePlan (ctx , killCtx context.Context , planfilePath string ) (* tfjson.Plan , error ) {
459404 ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
@@ -541,9 +486,11 @@ func (e *executor) graph(ctx, killCtx context.Context) (string, error) {
541486 // TODO: When the plan is present, we should probably use it?
542487 // "-plan=" + e.files.PlanFilePath(),
543488 }
489+
544490 if ver .GreaterThanOrEqual (version170 ) {
545491 args = append (args , "-type=plan" )
546492 }
493+
547494 var out strings.Builder
548495 cmd := exec .CommandContext (killCtx , e .binaryPath , args ... ) // #nosec
549496 cmd .Stdout = & out
@@ -602,53 +549,17 @@ func (e *executor) apply(
602549 return nil , xerrors .Errorf ("terraform apply: %w" , err )
603550 }
604551
605- // `terraform show` & `terraform graph`
606- state , err := e .stateResources (ctx , killCtx )
607- if err != nil {
608- return nil , err
609- }
610552 statefilePath := e .files .StateFilePath ()
611553 stateContent , err := os .ReadFile (statefilePath )
612554 if err != nil {
613555 return nil , xerrors .Errorf ("read statefile %q: %w" , statefilePath , err )
614556 }
615557
616558 return & proto.ApplyComplete {
617- Parameters : state .Parameters ,
618- Resources : state .Resources ,
619- ExternalAuthProviders : state .ExternalAuthProviders ,
620- State : stateContent ,
621- AiTasks : state .AITasks ,
559+ State : stateContent ,
622560 }, nil
623561}
624562
625- // stateResources must only be called while the lock is held.
626- func (e * executor ) stateResources (ctx , killCtx context.Context ) (* State , error ) {
627- ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
628- defer span .End ()
629-
630- state , err := e .state (ctx , killCtx )
631- if err != nil {
632- return nil , err
633- }
634- rawGraph , err := e .graph (ctx , killCtx )
635- if err != nil {
636- return nil , xerrors .Errorf ("get terraform graph: %w" , err )
637- }
638- converted := & State {}
639- if state .Values == nil {
640- return converted , nil
641- }
642-
643- converted , err = ConvertState (ctx , []* tfjson.StateModule {
644- state .Values .RootModule ,
645- }, rawGraph , e .server .logger )
646- if err != nil {
647- return nil , err
648- }
649- return converted , nil
650- }
651-
652563// state must only be called while the lock is held.
653564func (e * executor ) state (ctx , killCtx context.Context ) (* tfjson.State , error ) {
654565 ctx , span := e .server .startTrace (ctx , tracing .FuncName ())
0 commit comments