github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/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 "github.com/hashicorp/terraform/state" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 // backend.Local implementation. 16 func (b *Local) Context(op *backend.Operation) (*terraform.Context, state.State, error) { 17 // Make sure the type is invalid. We use this as a way to know not 18 // to ask for input/validate. 19 op.Type = backend.OperationTypeInvalid 20 21 return b.context(op) 22 } 23 24 func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State, error) { 25 // Get the state. 26 s, err := b.State(op.Workspace) 27 if err != nil { 28 return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) 29 } 30 31 if err := s.RefreshState(); err != nil { 32 return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) 33 } 34 35 // Initialize our context options 36 var opts terraform.ContextOpts 37 if v := b.ContextOpts; v != nil { 38 opts = *v 39 } 40 41 // Copy set options from the operation 42 opts.Destroy = op.Destroy 43 opts.Module = op.Module 44 opts.Targets = op.Targets 45 opts.UIInput = op.UIIn 46 if op.Variables != nil { 47 opts.Variables = op.Variables 48 } 49 50 // Load our state 51 opts.State = s.State() 52 53 // Build the context 54 var tfCtx *terraform.Context 55 if op.Plan != nil { 56 tfCtx, err = op.Plan.Context(&opts) 57 } else { 58 tfCtx, err = terraform.NewContext(&opts) 59 } 60 if err != nil { 61 return nil, nil, err 62 } 63 64 // If we have an operation, then we automatically do the input/validate 65 // here since every option requires this. 66 if op.Type != backend.OperationTypeInvalid { 67 // If input asking is enabled, then do that 68 if op.Plan == nil && b.OpInput { 69 mode := terraform.InputModeProvider 70 mode |= terraform.InputModeVar 71 mode |= terraform.InputModeVarUnset 72 73 if err := tfCtx.Input(mode); err != nil { 74 return nil, nil, errwrap.Wrapf("Error asking for user input: {{err}}", err) 75 } 76 } 77 78 // If validation is enabled, validate 79 if b.OpValidation { 80 // We ignore warnings here on purpose. We expect users to be listening 81 // to the terraform.Hook called after a validation. 82 ws, es := tfCtx.Validate() 83 if len(ws) > 0 { 84 // Log just in case the CLI isn't enabled 85 log.Printf("[WARN] backend/local: %d warnings: %v", len(ws), ws) 86 87 // If we have a CLI, output the warnings 88 if b.CLI != nil { 89 b.CLI.Warn(strings.TrimSpace(validateWarnHeader) + "\n") 90 for _, w := range ws { 91 b.CLI.Warn(fmt.Sprintf(" * %s", w)) 92 } 93 94 // Make a newline before continuing 95 b.CLI.Output("") 96 } 97 } 98 99 if len(es) > 0 { 100 return nil, nil, multierror.Append(nil, es...) 101 } 102 } 103 } 104 105 return tfCtx, s, nil 106 } 107 108 const validateWarnHeader = ` 109 There are warnings related to your configuration. If no errors occurred, 110 Terraform will continue despite these warnings. It is a good idea to resolve 111 these warnings in the near future. 112 113 Warnings: 114 `