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