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  }