github.com/tompao/terraform@v0.6.10-0.20180215233341-e41b29d0961b/backend/local/backend_local.go (about)

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