github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/backend/backend.go (about) 1 // Package backend provides interfaces that the CLI uses to interact with 2 // Terraform. A backend provides the abstraction that allows the same CLI 3 // to simultaneously support both local and remote operations for seamlessly 4 // using Terraform in a team environment. 5 package backend 6 7 import ( 8 "context" 9 "errors" 10 "time" 11 12 "github.com/hashicorp/terraform/addrs" 13 "github.com/hashicorp/terraform/command/clistate" 14 "github.com/hashicorp/terraform/configs" 15 "github.com/hashicorp/terraform/configs/configload" 16 "github.com/hashicorp/terraform/configs/configschema" 17 "github.com/hashicorp/terraform/plans" 18 "github.com/hashicorp/terraform/plans/planfile" 19 "github.com/hashicorp/terraform/states" 20 "github.com/hashicorp/terraform/states/statemgr" 21 "github.com/hashicorp/terraform/terraform" 22 "github.com/hashicorp/terraform/tfdiags" 23 "github.com/zclconf/go-cty/cty" 24 ) 25 26 // DefaultStateName is the name of the default, initial state that every 27 // backend must have. This state cannot be deleted. 28 const DefaultStateName = "default" 29 30 var ( 31 // ErrDefaultWorkspaceNotSupported is returned when an operation does not 32 // support using the default workspace, but requires a named workspace to 33 // be selected. 34 ErrDefaultWorkspaceNotSupported = errors.New("default workspace not supported\n" + 35 "You can create a new workspace with the \"workspace new\" command.") 36 37 // ErrOperationNotSupported is returned when an unsupported operation 38 // is detected by the configured backend. 39 ErrOperationNotSupported = errors.New("operation not supported") 40 41 // ErrWorkspacesNotSupported is an error returned when a caller attempts 42 // to perform an operation on a workspace other than "default" for a 43 // backend that doesn't support multiple workspaces. 44 // 45 // The caller can detect this to do special fallback behavior or produce 46 // a specific, helpful error message. 47 ErrWorkspacesNotSupported = errors.New("workspaces not supported") 48 ) 49 50 // InitFn is used to initialize a new backend. 51 type InitFn func() Backend 52 53 // Backend is the minimal interface that must be implemented to enable Terraform. 54 type Backend interface { 55 // ConfigSchema returns a description of the expected configuration 56 // structure for the receiving backend. 57 // 58 // This method does not have any side-effects for the backend and can 59 // be safely used before configuring. 60 ConfigSchema() *configschema.Block 61 62 // PrepareConfig checks the validity of the values in the given 63 // configuration, and inserts any missing defaults, assuming that its 64 // structure has already been validated per the schema returned by 65 // ConfigSchema. 66 // 67 // This method does not have any side-effects for the backend and can 68 // be safely used before configuring. It also does not consult any 69 // external data such as environment variables, disk files, etc. Validation 70 // that requires such external data should be deferred until the 71 // Configure call. 72 // 73 // If error diagnostics are returned then the configuration is not valid 74 // and must not subsequently be passed to the Configure method. 75 // 76 // This method may return configuration-contextual diagnostics such 77 // as tfdiags.AttributeValue, and so the caller should provide the 78 // necessary context via the diags.InConfigBody method before returning 79 // diagnostics to the user. 80 PrepareConfig(cty.Value) (cty.Value, tfdiags.Diagnostics) 81 82 // Configure uses the provided configuration to set configuration fields 83 // within the backend. 84 // 85 // The given configuration is assumed to have already been validated 86 // against the schema returned by ConfigSchema and passed validation 87 // via PrepareConfig. 88 // 89 // This method may be called only once per backend instance, and must be 90 // called before all other methods except where otherwise stated. 91 // 92 // If error diagnostics are returned, the internal state of the instance 93 // is undefined and no other methods may be called. 94 Configure(cty.Value) tfdiags.Diagnostics 95 96 // StateMgr returns the state manager for the given workspace name. 97 // 98 // If the returned state manager also implements statemgr.Locker then 99 // it's the caller's responsibility to call Lock and Unlock as appropriate. 100 // 101 // If the named workspace doesn't exist, or if it has no state, it will 102 // be created either immediately on this call or the first time 103 // PersistState is called, depending on the state manager implementation. 104 StateMgr(workspace string) (statemgr.Full, error) 105 106 // StateMgrWithoutCheckVersion returns the state manager for the given 107 // workspace name, while ensuring that Terraform version checks are not 108 // performed if the backend needs to read a state file in order to 109 // initialize the state manager. 110 // 111 // For backends which do not need to read a state file at this point, this 112 // is identical to StateMgr. 113 // 114 // This is used to facilitate reading compatible state files from newer 115 // versions of Terraform. 116 StateMgrWithoutCheckVersion(workspace string) (statemgr.Full, error) 117 118 // DeleteWorkspace removes the workspace with the given name if it exists. 119 // 120 // DeleteWorkspace cannot prevent deleting a state that is in use. It is 121 // the responsibility of the caller to hold a Lock for the state manager 122 // belonging to this workspace before calling this method. 123 DeleteWorkspace(name string) error 124 125 // States returns a list of the names of all of the workspaces that exist 126 // in this backend. 127 Workspaces() ([]string, error) 128 } 129 130 // Enhanced implements additional behavior on top of a normal backend. 131 // 132 // Enhanced backends allow customizing the behavior of Terraform operations. 133 // This allows Terraform to potentially run operations remotely, load 134 // configurations from external sources, etc. 135 type Enhanced interface { 136 Backend 137 138 // Operation performs a Terraform operation such as refresh, plan, apply. 139 // It is up to the implementation to determine what "performing" means. 140 // This DOES NOT BLOCK. The context returned as part of RunningOperation 141 // should be used to block for completion. 142 // If the state used in the operation can be locked, it is the 143 // responsibility of the Backend to lock the state for the duration of the 144 // running operation. 145 Operation(context.Context, *Operation) (*RunningOperation, error) 146 } 147 148 // Local implements additional behavior on a Backend that allows local 149 // operations in addition to remote operations. 150 // 151 // This enables more behaviors of Terraform that require more data such 152 // as `console`, `import`, `graph`. These require direct access to 153 // configurations, variables, and more. Not all backends may support this 154 // so we separate it out into its own optional interface. 155 type Local interface { 156 // Context returns a runnable terraform Context. The operation parameter 157 // doesn't need a Type set but it needs other options set such as Module. 158 Context(*Operation) (*terraform.Context, statemgr.Full, tfdiags.Diagnostics) 159 } 160 161 // An operation represents an operation for Terraform to execute. 162 // 163 // Note that not all fields are supported by all backends and can result 164 // in an error if set. All backend implementations should show user-friendly 165 // errors explaining any incorrectly set values. For example, the local 166 // backend doesn't support a PlanId being set. 167 // 168 // The operation options are purposely designed to have maximal compatibility 169 // between Terraform and Terraform Servers (a commercial product offered by 170 // HashiCorp). Therefore, it isn't expected that other implementation support 171 // every possible option. The struct here is generalized in order to allow 172 // even partial implementations to exist in the open, without walling off 173 // remote functionality 100% behind a commercial wall. Anyone can implement 174 // against this interface and have Terraform interact with it just as it 175 // would with HashiCorp-provided Terraform Servers. 176 type Operation struct { 177 // Type is the operation to perform. 178 Type OperationType 179 180 // PlanId is an opaque value that backends can use to execute a specific 181 // plan for an apply operation. 182 // 183 // PlanOutBackend is the backend to store with the plan. This is the 184 // backend that will be used when applying the plan. 185 PlanId string 186 PlanRefresh bool // PlanRefresh will do a refresh before a plan 187 PlanOutPath string // PlanOutPath is the path to save the plan 188 PlanOutBackend *plans.Backend 189 190 // ConfigDir is the path to the directory containing the configuration's 191 // root module. 192 ConfigDir string 193 194 // ConfigLoader is a configuration loader that can be used to load 195 // configuration from ConfigDir. 196 ConfigLoader *configload.Loader 197 198 // Plan is a plan that was passed as an argument. This is valid for 199 // plan and apply arguments but may not work for all backends. 200 PlanFile *planfile.Reader 201 202 // The options below are more self-explanatory and affect the runtime 203 // behavior of the operation. 204 AutoApprove bool 205 Destroy bool 206 DestroyForce bool 207 Parallelism int 208 Targets []addrs.Targetable 209 Variables map[string]UnparsedVariableValue 210 211 // Some operations use root module variables only opportunistically or 212 // don't need them at all. If this flag is set, the backend must treat 213 // all variables as optional and provide an unknown value for any required 214 // variables that aren't set in order to allow partial evaluation against 215 // the resulting incomplete context. 216 // 217 // This flag is honored only if PlanFile isn't set. If PlanFile is set then 218 // the variables set in the plan are used instead, and they must be valid. 219 AllowUnsetVariables bool 220 221 // Input/output/control options. 222 UIIn terraform.UIInput 223 UIOut terraform.UIOutput 224 225 // If LockState is true, the Operation must Lock any 226 // state.Lockers for its duration, and Unlock when complete. 227 LockState bool 228 229 // StateLocker is used to lock the state while providing UI feedback to the 230 // user. This will be supplied by the Backend itself. 231 StateLocker clistate.Locker 232 233 // The duration to retry obtaining a State lock. 234 StateLockTimeout time.Duration 235 236 // Workspace is the name of the workspace that this operation should run 237 // in, which controls which named state is used. 238 Workspace string 239 } 240 241 // HasConfig returns true if and only if the operation has a ConfigDir value 242 // that refers to a directory containing at least one Terraform configuration 243 // file. 244 func (o *Operation) HasConfig() bool { 245 return o.ConfigLoader.IsConfigDir(o.ConfigDir) 246 } 247 248 // Config loads the configuration that the operation applies to, using the 249 // ConfigDir and ConfigLoader fields within the receiving operation. 250 func (o *Operation) Config() (*configs.Config, tfdiags.Diagnostics) { 251 var diags tfdiags.Diagnostics 252 config, hclDiags := o.ConfigLoader.LoadConfig(o.ConfigDir) 253 diags = diags.Append(hclDiags) 254 return config, diags 255 } 256 257 // RunningOperation is the result of starting an operation. 258 type RunningOperation struct { 259 // For implementers of a backend, this context should not wrap the 260 // passed in context. Otherwise, cancelling the parent context will 261 // immediately mark this context as "done" but those aren't the semantics 262 // we want: we want this context to be done only when the operation itself 263 // is fully done. 264 context.Context 265 266 // Stop requests the operation to complete early, by calling Stop on all 267 // the plugins. If the process needs to terminate immediately, call Cancel. 268 Stop context.CancelFunc 269 270 // Cancel is the context.CancelFunc associated with the embedded context, 271 // and can be called to terminate the operation early. 272 // Once Cancel is called, the operation should return as soon as possible 273 // to avoid running operations during process exit. 274 Cancel context.CancelFunc 275 276 // Result is the exit status of the operation, populated only after the 277 // operation has completed. 278 Result OperationResult 279 280 // PlanEmpty is populated after a Plan operation completes without error 281 // to note whether a plan is empty or has changes. 282 PlanEmpty bool 283 284 // State is the final state after the operation completed. Persisting 285 // this state is managed by the backend. This should only be read 286 // after the operation completes to avoid read/write races. 287 State *states.State 288 } 289 290 // OperationResult describes the result status of an operation. 291 type OperationResult int 292 293 const ( 294 // OperationSuccess indicates that the operation completed as expected. 295 OperationSuccess OperationResult = 0 296 297 // OperationFailure indicates that the operation encountered some sort 298 // of error, and thus may have been only partially performed or not 299 // performed at all. 300 OperationFailure OperationResult = 1 301 ) 302 303 func (r OperationResult) ExitStatus() int { 304 return int(r) 305 }