github.com/sixgill/terraform@v0.9.0-beta2.0.20170316214032-033f6226ae50/backend/local/backend_refresh.go (about)

     1  package local
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/errwrap"
    10  	"github.com/hashicorp/go-multierror"
    11  	"github.com/hashicorp/terraform/backend"
    12  	clistate "github.com/hashicorp/terraform/command/state"
    13  	"github.com/hashicorp/terraform/config/module"
    14  	"github.com/hashicorp/terraform/state"
    15  )
    16  
    17  func (b *Local) opRefresh(
    18  	ctx context.Context,
    19  	op *backend.Operation,
    20  	runningOp *backend.RunningOperation) {
    21  	// Check if our state exists if we're performing a refresh operation. We
    22  	// only do this if we're managing state with this backend.
    23  	if b.Backend == nil {
    24  		if _, err := os.Stat(b.StatePath); err != nil {
    25  			if os.IsNotExist(err) {
    26  				err = nil
    27  			}
    28  
    29  			if err != nil {
    30  				runningOp.Err = fmt.Errorf(
    31  					"There was an error reading the Terraform state that is needed\n"+
    32  						"for refreshing. The path and error are shown below.\n\n"+
    33  						"Path: %s\n\nError: %s",
    34  					b.StatePath, err)
    35  				return
    36  			}
    37  		}
    38  	}
    39  
    40  	// If we have no config module given to use, create an empty tree to
    41  	// avoid crashes when Terraform.Context is initialized.
    42  	if op.Module == nil {
    43  		op.Module = module.NewEmptyTree()
    44  	}
    45  
    46  	// Get our context
    47  	tfCtx, opState, err := b.context(op)
    48  	if err != nil {
    49  		runningOp.Err = err
    50  		return
    51  	}
    52  
    53  	if op.LockState {
    54  		lockInfo := state.NewLockInfo()
    55  		lockInfo.Operation = op.Type.String()
    56  		lockID, err := clistate.Lock(opState, lockInfo, b.CLI, b.Colorize())
    57  		if err != nil {
    58  			runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
    59  			return
    60  		}
    61  
    62  		defer func() {
    63  			if err := clistate.Unlock(opState, lockID, b.CLI, b.Colorize()); err != nil {
    64  				runningOp.Err = multierror.Append(runningOp.Err, err)
    65  			}
    66  		}()
    67  	}
    68  
    69  	// Set our state
    70  	runningOp.State = opState.State()
    71  	if runningOp.State.Empty() || !runningOp.State.HasResources() {
    72  		if b.CLI != nil {
    73  			b.CLI.Output(b.Colorize().Color(
    74  				strings.TrimSpace(refreshNoState) + "\n"))
    75  		}
    76  	}
    77  
    78  	// Perform operation and write the resulting state to the running op
    79  	newState, err := tfCtx.Refresh()
    80  	runningOp.State = newState
    81  	if err != nil {
    82  		runningOp.Err = errwrap.Wrapf("Error refreshing state: {{err}}", err)
    83  		return
    84  	}
    85  
    86  	// Write and persist the state
    87  	if err := opState.WriteState(newState); err != nil {
    88  		runningOp.Err = errwrap.Wrapf("Error writing state: {{err}}", err)
    89  		return
    90  	}
    91  	if err := opState.PersistState(); err != nil {
    92  		runningOp.Err = errwrap.Wrapf("Error saving state: {{err}}", err)
    93  		return
    94  	}
    95  }
    96  
    97  const refreshNoState = `
    98  [reset][bold][yellow]Empty or non-existent state file.[reset][yellow]
    99  
   100  Refresh will do nothing. Refresh does not error or return an erroneous
   101  exit status because many automation scripts use refresh, plan, then apply
   102  and may not have a state file yet for the first run.
   103  `