opentofu/terraform/context.go

129 lines
3.5 KiB
Go
Raw Normal View History

2015-02-04 17:44:23 -06:00
package terraform
import (
"sync"
2015-02-07 11:53:46 -06:00
"github.com/hashicorp/go-multierror"
2015-02-04 17:44:23 -06:00
"github.com/hashicorp/terraform/config/module"
)
// ContextOpts are the user-configurable options to create a context with
// NewContext.
type ContextOpts struct {
Diff *Diff
Hooks []Hook
Module *module.Tree
Parallelism int
State *State
Providers map[string]ResourceProviderFactory
Provisioners map[string]ResourceProvisionerFactory
Variables map[string]string
UIInput UIInput
}
// Context represents all the context that Terraform needs in order to
// perform operations on infrastructure. This structure is built using
// NewContext. See the documentation for that.
type Context2 struct {
2015-02-09 13:15:54 -06:00
module *module.Tree
providers map[string]ResourceProviderFactory
provisioners map[string]ResourceProvisionerFactory
state *State
stateLock sync.RWMutex
variables map[string]string
2015-02-04 17:44:23 -06:00
}
// NewContext creates a new Context structure.
//
// Once a Context is creator, the pointer values within ContextOpts
// should not be mutated in any way, since the pointers are copied, not
// the values themselves.
func NewContext2(opts *ContextOpts) *Context2 {
return &Context2{
2015-02-09 13:15:54 -06:00
module: opts.Module,
providers: opts.Providers,
provisioners: opts.Provisioners,
state: opts.State,
variables: opts.Variables,
2015-02-04 17:44:23 -06:00
}
}
// GraphBuilder returns the GraphBuilder that will be used to create
// the graphs for this context.
func (c *Context2) GraphBuilder() GraphBuilder {
// TODO test
providers := make([]string, 0, len(c.providers))
for k, _ := range c.providers {
providers = append(providers, k)
}
2015-02-09 13:15:54 -06:00
provisioners := make([]string, 0, len(c.provisioners))
for k, _ := range c.provisioners {
provisioners = append(provisioners, k)
}
2015-02-04 17:44:23 -06:00
return &BuiltinGraphBuilder{
2015-02-09 13:15:54 -06:00
Root: c.module,
Providers: providers,
Provisioners: provisioners,
State: c.state,
2015-02-04 17:44:23 -06:00
}
}
// Refresh goes through all the resources in the state and refreshes them
// to their latest state. This will update the state that this context
// works with, along with returning it.
//
// Even in the case an error is returned, the state will be returned and
// will potentially be partially updated.
func (c *Context2) Refresh() (*State, []error) {
if _, err := c.walk(walkRefresh); err != nil {
var errs error
return nil, multierror.Append(errs, err).Errors
}
2015-02-11 10:48:45 -06:00
return c.state, nil
}
2015-02-04 17:44:23 -06:00
// Validate validates the configuration and returns any warnings or errors.
func (c *Context2) Validate() ([]string, []error) {
2015-02-07 11:53:46 -06:00
var errs error
2015-02-04 19:02:18 -06:00
// Validate the configuration itself
if err := c.module.Validate(); err != nil {
2015-02-07 11:53:46 -06:00
errs = multierror.Append(errs, err)
}
// This only needs to be done for the root module, since inter-module
// variables are validated in the module tree.
if config := c.module.Config(); config != nil {
// Validate the user variables
if err := smcUserVariables(config, c.variables); len(err) > 0 {
errs = multierror.Append(errs, err...)
}
2015-02-04 19:02:18 -06:00
}
// Walk
walker, err := c.walk(walkValidate)
2015-02-04 17:44:23 -06:00
if err != nil {
return nil, multierror.Append(errs, err).Errors
2015-02-04 17:44:23 -06:00
}
// Return the result
rerrs := multierror.Append(errs, walker.ValidationErrors...)
return walker.ValidationWarnings, rerrs.Errors
2015-02-04 17:44:23 -06:00
}
func (c *Context2) walk(operation walkOperation) (*ContextGraphWalker, error) {
// Build the graph
graph, err := c.GraphBuilder().Build(RootModulePath)
if err != nil {
return nil, err
}
// Walk the graph
walker := &ContextGraphWalker{Context: c, Operation: operation}
return walker, graph.Walk(walker)
}