github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/backend/local/backend_refresh.go (about) 1 package local 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 9 "github.com/hashicorp/errwrap" 10 "github.com/iaas-resource-provision/iaas-rpc/internal/backend" 11 "github.com/iaas-resource-provision/iaas-rpc/internal/states" 12 "github.com/iaas-resource-provision/iaas-rpc/internal/states/statemgr" 13 "github.com/iaas-resource-provision/iaas-rpc/internal/tfdiags" 14 ) 15 16 func (b *Local) opRefresh( 17 stopCtx context.Context, 18 cancelCtx context.Context, 19 op *backend.Operation, 20 runningOp *backend.RunningOperation) { 21 22 var diags tfdiags.Diagnostics 23 24 // Check if our state exists if we're performing a refresh operation. We 25 // only do this if we're managing state with this backend. 26 if b.Backend == nil { 27 if _, err := os.Stat(b.StatePath); err != nil { 28 if os.IsNotExist(err) { 29 err = nil 30 } 31 32 if err != nil { 33 diags = diags.Append(tfdiags.Sourceless( 34 tfdiags.Error, 35 "Cannot read state file", 36 fmt.Sprintf("Failed to read %s: %s", b.StatePath, err), 37 )) 38 op.ReportResult(runningOp, diags) 39 return 40 } 41 } 42 } 43 44 // Refresh now happens via a plan, so we need to ensure this is enabled 45 op.PlanRefresh = true 46 47 // Get our context 48 tfCtx, _, opState, contextDiags := b.context(op) 49 diags = diags.Append(contextDiags) 50 if contextDiags.HasErrors() { 51 op.ReportResult(runningOp, diags) 52 return 53 } 54 55 // the state was locked during succesfull context creation; unlock the state 56 // when the operation completes 57 defer func() { 58 diags := op.StateLocker.Unlock() 59 if diags.HasErrors() { 60 op.View.Diagnostics(diags) 61 runningOp.Result = backend.OperationFailure 62 } 63 }() 64 65 // Set our state 66 runningOp.State = opState.State() 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 = tfCtx.Refresh() 82 log.Printf("[INFO] backend/local: refresh calling Refresh") 83 }() 84 85 if b.opWait(doneCh, stopCtx, cancelCtx, tfCtx, 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(errwrap.Wrapf("Failed to write state: {{err}}", err)) 100 op.ReportResult(runningOp, diags) 101 return 102 } 103 104 // Show any remaining warnings before exiting 105 op.ReportResult(runningOp, diags) 106 }