github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/backend/local/backend_local.go (about) 1 package local 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/errwrap" 9 "github.com/hashicorp/go-multierror" 10 "github.com/hashicorp/terraform/backend" 11 clistate "github.com/hashicorp/terraform/command/state" 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() 28 if err != nil { 29 return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) 30 } 31 32 if op.LockState { 33 err := clistate.Lock(s, op.Type.String(), b.CLI, b.Colorize()) 34 if err != nil { 35 return nil, nil, errwrap.Wrapf("Error locking state: {{err}}", err) 36 } 37 } 38 39 if err := s.RefreshState(); err != nil { 40 return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) 41 } 42 43 // Initialize our context options 44 var opts terraform.ContextOpts 45 if v := b.ContextOpts; v != nil { 46 opts = *v 47 } 48 49 // Copy set options from the operation 50 opts.Destroy = op.Destroy 51 opts.Module = op.Module 52 opts.Targets = op.Targets 53 opts.UIInput = op.UIIn 54 if op.Variables != nil { 55 opts.Variables = op.Variables 56 } 57 58 // Load our state 59 opts.State = s.State() 60 61 // Build the context 62 var tfCtx *terraform.Context 63 if op.Plan != nil { 64 tfCtx, err = op.Plan.Context(&opts) 65 } else { 66 tfCtx, err = terraform.NewContext(&opts) 67 } 68 if err != nil { 69 return nil, nil, err 70 } 71 72 // If we have an operation, then we automatically do the input/validate 73 // here since every option requires this. 74 if op.Type != backend.OperationTypeInvalid { 75 // If input asking is enabled, then do that 76 if op.Plan == nil && b.OpInput { 77 mode := terraform.InputModeProvider 78 mode |= terraform.InputModeVar 79 mode |= terraform.InputModeVarUnset 80 81 if err := tfCtx.Input(mode); err != nil { 82 return nil, nil, errwrap.Wrapf("Error asking for user input: {{err}}", err) 83 } 84 } 85 86 // If validation is enabled, validate 87 if b.OpValidation { 88 // We ignore warnings here on purpose. We expect users to be listening 89 // to the terraform.Hook called after a validation. 90 ws, es := tfCtx.Validate() 91 if len(ws) > 0 { 92 // Log just in case the CLI isn't enabled 93 log.Printf("[WARN] backend/local: %d warnings: %v", len(ws), ws) 94 95 // If we have a CLI, output the warnings 96 if b.CLI != nil { 97 b.CLI.Warn(strings.TrimSpace(validateWarnHeader) + "\n") 98 for _, w := range ws { 99 b.CLI.Warn(fmt.Sprintf(" * %s", w)) 100 } 101 102 // Make a newline before continuing 103 b.CLI.Output("") 104 } 105 } 106 107 if len(es) > 0 { 108 return nil, nil, multierror.Append(nil, es...) 109 } 110 } 111 } 112 113 return tfCtx, s, nil 114 } 115 116 const validateWarnHeader = ` 117 There are warnings related to your configuration. If no errors occurred, 118 Terraform will continue despite these warnings. It is a good idea to resolve 119 these warnings in the near future. 120 121 Warnings: 122 `