github.com/hugorut/terraform@v1.1.3/src/backend/local/backend_refresh.go (about)

     1  package local
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  
     9  	"github.com/hugorut/terraform/src/backend"
    10  	"github.com/hugorut/terraform/src/logging"
    11  	"github.com/hugorut/terraform/src/states"
    12  	"github.com/hugorut/terraform/src/states/statemgr"
    13  	"github.com/hugorut/terraform/src/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  	lr, _, opState, contextDiags := b.localRun(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  	// If we succeed then we'll overwrite this with the resulting state below,
    66  	// but otherwise the resulting state is just the input state.
    67  	runningOp.State = lr.InputState
    68  	if !runningOp.State.HasManagedResourceInstanceObjects() {
    69  		diags = diags.Append(tfdiags.Sourceless(
    70  			tfdiags.Warning,
    71  			"Empty or non-existent state",
    72  			"There are currently no remote objects tracked in the state, so there is nothing to refresh.",
    73  		))
    74  	}
    75  
    76  	// Perform the refresh in a goroutine so we can be interrupted
    77  	var newState *states.State
    78  	var refreshDiags tfdiags.Diagnostics
    79  	doneCh := make(chan struct{})
    80  	go func() {
    81  		defer logging.PanicHandler()
    82  		defer close(doneCh)
    83  		newState, refreshDiags = lr.Core.Refresh(lr.Config, lr.InputState, lr.PlanOpts)
    84  		log.Printf("[INFO] backend/local: refresh calling Refresh")
    85  	}()
    86  
    87  	if b.opWait(doneCh, stopCtx, cancelCtx, lr.Core, opState, op.View) {
    88  		return
    89  	}
    90  
    91  	// Write the resulting state to the running op
    92  	runningOp.State = newState
    93  	diags = diags.Append(refreshDiags)
    94  	if refreshDiags.HasErrors() {
    95  		op.ReportResult(runningOp, diags)
    96  		return
    97  	}
    98  
    99  	err := statemgr.WriteAndPersist(opState, newState)
   100  	if err != nil {
   101  		diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
   102  		op.ReportResult(runningOp, diags)
   103  		return
   104  	}
   105  
   106  	// Show any remaining warnings before exiting
   107  	op.ReportResult(runningOp, diags)
   108  }