github.com/hooklift/terraform@v0.11.0-beta1.0.20171117000744-6786c1361ffe/backend/local/backend_local.go (about)

     1  package local
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/errwrap"
    10  	"github.com/hashicorp/go-multierror"
    11  	"github.com/hashicorp/terraform/backend"
    12  	"github.com/hashicorp/terraform/state"
    13  	"github.com/hashicorp/terraform/terraform"
    14  )
    15  
    16  // backend.Local implementation.
    17  func (b *Local) Context(op *backend.Operation) (*terraform.Context, state.State, error) {
    18  	// Make sure the type is invalid. We use this as a way to know not
    19  	// to ask for input/validate.
    20  	op.Type = backend.OperationTypeInvalid
    21  
    22  	return b.context(op)
    23  }
    24  
    25  func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State, error) {
    26  	// Get the state.
    27  	s, err := b.State(op.Workspace)
    28  	if err != nil {
    29  		return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
    30  	}
    31  
    32  	if err := s.RefreshState(); err != nil {
    33  		return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
    34  	}
    35  
    36  	// Initialize our context options
    37  	var opts terraform.ContextOpts
    38  	if v := b.ContextOpts; v != nil {
    39  		opts = *v
    40  	}
    41  
    42  	// Copy set options from the operation
    43  	opts.Destroy = op.Destroy
    44  	opts.Module = op.Module
    45  	opts.Targets = op.Targets
    46  	opts.UIInput = op.UIIn
    47  	if op.Variables != nil {
    48  		opts.Variables = op.Variables
    49  	}
    50  
    51  	// Load our state
    52  	// By the time we get here, the backend creation code in "command" took
    53  	// care of making s.State() return a state compatible with our plan,
    54  	// if any, so we can safely pass this value in both the plan context
    55  	// and new context cases below.
    56  	opts.State = s.State()
    57  
    58  	// Build the context
    59  	var tfCtx *terraform.Context
    60  	if op.Plan != nil {
    61  		tfCtx, err = op.Plan.Context(&opts)
    62  	} else {
    63  		tfCtx, err = terraform.NewContext(&opts)
    64  	}
    65  
    66  	// any errors resolving plugins returns this
    67  	if rpe, ok := err.(*terraform.ResourceProviderError); ok {
    68  		b.pluginInitRequired(rpe)
    69  		// we wrote the full UI error here, so return a generic error for flow
    70  		// control in the command.
    71  		return nil, nil, errors.New("error satisfying plugin requirements")
    72  	}
    73  
    74  	if err != nil {
    75  		return nil, nil, err
    76  	}
    77  
    78  	// If we have an operation, then we automatically do the input/validate
    79  	// here since every option requires this.
    80  	if op.Type != backend.OperationTypeInvalid {
    81  		// If input asking is enabled, then do that
    82  		if op.Plan == nil && b.OpInput {
    83  			mode := terraform.InputModeProvider
    84  			mode |= terraform.InputModeVar
    85  			mode |= terraform.InputModeVarUnset
    86  
    87  			if err := tfCtx.Input(mode); err != nil {
    88  				return nil, nil, errwrap.Wrapf("Error asking for user input: {{err}}", err)
    89  			}
    90  		}
    91  
    92  		// If validation is enabled, validate
    93  		if b.OpValidation {
    94  			// We ignore warnings here on purpose. We expect users to be listening
    95  			// to the terraform.Hook called after a validation.
    96  			ws, es := tfCtx.Validate()
    97  			if len(ws) > 0 {
    98  				// Log just in case the CLI isn't enabled
    99  				log.Printf("[WARN] backend/local: %d warnings: %v", len(ws), ws)
   100  
   101  				// If we have a CLI, output the warnings
   102  				if b.CLI != nil {
   103  					b.CLI.Warn(strings.TrimSpace(validateWarnHeader) + "\n")
   104  					for _, w := range ws {
   105  						b.CLI.Warn(fmt.Sprintf("  * %s", w))
   106  					}
   107  
   108  					// Make a newline before continuing
   109  					b.CLI.Output("")
   110  				}
   111  			}
   112  
   113  			if len(es) > 0 {
   114  				return nil, nil, multierror.Append(nil, es...)
   115  			}
   116  		}
   117  	}
   118  
   119  	return tfCtx, s, nil
   120  }
   121  
   122  const validateWarnHeader = `
   123  There are warnings related to your configuration. If no errors occurred,
   124  Terraform will continue despite these warnings. It is a good idea to resolve
   125  these warnings in the near future.
   126  
   127  Warnings:
   128  `