kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/backend/local/backend_refresh.go (about) 1 package local 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 9 "kubeform.dev/terraform-backend-sdk/backend" 10 "kubeform.dev/terraform-backend-sdk/states" 11 "kubeform.dev/terraform-backend-sdk/states/statemgr" 12 "kubeform.dev/terraform-backend-sdk/tfdiags" 13 ) 14 15 func (b *Local) opRefresh( 16 stopCtx context.Context, 17 cancelCtx context.Context, 18 op *backend.Operation, 19 runningOp *backend.RunningOperation) { 20 21 var diags tfdiags.Diagnostics 22 23 // Check if our state exists if we're performing a refresh operation. We 24 // only do this if we're managing state with this backend. 25 if b.Backend == nil { 26 if _, err := os.Stat(b.StatePath); err != nil { 27 if os.IsNotExist(err) { 28 err = nil 29 } 30 31 if err != nil { 32 diags = diags.Append(tfdiags.Sourceless( 33 tfdiags.Error, 34 "Cannot read state file", 35 fmt.Sprintf("Failed to read %s: %s", b.StatePath, err), 36 )) 37 op.ReportResult(runningOp, diags) 38 return 39 } 40 } 41 } 42 43 // Refresh now happens via a plan, so we need to ensure this is enabled 44 op.PlanRefresh = true 45 46 // Get our context 47 lr, _, opState, contextDiags := b.localRun(op) 48 diags = diags.Append(contextDiags) 49 if contextDiags.HasErrors() { 50 op.ReportResult(runningOp, diags) 51 return 52 } 53 54 // the state was locked during succesfull context creation; unlock the state 55 // when the operation completes 56 defer func() { 57 diags := op.StateLocker.Unlock() 58 if diags.HasErrors() { 59 op.View.Diagnostics(diags) 60 runningOp.Result = backend.OperationFailure 61 } 62 }() 63 64 // If we succeed then we'll overwrite this with the resulting state below, 65 // but otherwise the resulting state is just the input state. 66 runningOp.State = lr.InputState 67 if !runningOp.State.HasResources() { 68 diags = diags.Append(tfdiags.Sourceless( 69 tfdiags.Warning, 70 "Empty or non-existent state", 71 "There are currently no resources tracked in the state, so there is nothing to refresh.", 72 )) 73 } 74 75 // Perform the refresh in a goroutine so we can be interrupted 76 var newState *states.State 77 var refreshDiags tfdiags.Diagnostics 78 doneCh := make(chan struct{}) 79 go func() { 80 defer close(doneCh) 81 newState, refreshDiags = lr.Core.Refresh(lr.Config, lr.InputState, lr.PlanOpts) 82 log.Printf("[INFO] backend/local: refresh calling Refresh") 83 }() 84 85 if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) { 86 return 87 } 88 89 // Write the resulting state to the running op 90 runningOp.State = newState 91 diags = diags.Append(refreshDiags) 92 if refreshDiags.HasErrors() { 93 op.ReportResult(runningOp, diags) 94 return 95 } 96 97 err := statemgr.WriteAndPersist(opState, newState) 98 if err != nil { 99 diags = diags.Append(fmt.Errorf("failed to write state: %w", err)) 100 op.ReportResult(runningOp, diags) 101 return 102 } 103 104 // Show any remaining warnings before exiting 105 op.ReportResult(runningOp, diags) 106 }