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