terraform: make our own graph meta
This commit is contained in:
parent
b6272a4a69
commit
0bf394dfe2
|
@ -11,19 +11,40 @@ import (
|
||||||
// graph. This node is just a placemarker and has no associated functionality.
|
// graph. This node is just a placemarker and has no associated functionality.
|
||||||
const GraphRootNode = "root"
|
const GraphRootNode = "root"
|
||||||
|
|
||||||
|
// GraphNodeResource is a node type in the graph that represents a resource.
|
||||||
|
type GraphNodeResource struct {
|
||||||
|
Type string
|
||||||
|
Config *config.Resource
|
||||||
|
Orphan bool
|
||||||
|
Resource *Resource
|
||||||
|
ResourceProviderID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeResourceProvider is a node type in the graph that represents
|
||||||
|
// the configuration for a resource provider.
|
||||||
|
type GraphNodeResourceProvider struct {
|
||||||
|
ID string
|
||||||
|
Provider ResourceProvider
|
||||||
|
Config *config.ProviderConfig
|
||||||
|
}
|
||||||
|
|
||||||
// Graph builds a dependency graph for the given configuration and state.
|
// Graph builds a dependency graph for the given configuration and state.
|
||||||
//
|
//
|
||||||
|
// Before using this graph, Validate should be called on it. This will perform
|
||||||
|
// some initialization necessary such as setting up a root node. This function
|
||||||
|
// doesn't perform the Validate automatically in case the caller wants to
|
||||||
|
// modify the graph.
|
||||||
|
//
|
||||||
// This dependency graph shows the correct order that any resources need
|
// This dependency graph shows the correct order that any resources need
|
||||||
// to be operated on.
|
// to be operated on.
|
||||||
//
|
//
|
||||||
// The Meta field of a graph Noun can contain one of the follow types. A
|
// The Meta field of a graph Noun can contain one of the follow types. A
|
||||||
// description is next to each type to explain what it is.
|
// description is next to each type to explain what it is.
|
||||||
//
|
//
|
||||||
// *config.Resource - A resource itself
|
// *GraphNodeResource - A resource. See the documentation of this
|
||||||
// *config.ProviderConfig - The configuration for a provider that
|
// struct for more details.
|
||||||
// should be initialized.
|
// *GraphNodeResourceProvider - A resource provider that needs to be
|
||||||
// *ResourceState - An orphan resource that we only have the state of
|
// configured at this point.
|
||||||
// and no more configuration.
|
|
||||||
//
|
//
|
||||||
func Graph(c *config.Config, s *State) *depgraph.Graph {
|
func Graph(c *config.Config, s *State) *depgraph.Graph {
|
||||||
g := new(depgraph.Graph)
|
g := new(depgraph.Graph)
|
||||||
|
@ -56,7 +77,10 @@ func graphAddConfigResources(g *depgraph.Graph, c *config.Config) {
|
||||||
for _, r := range c.Resources {
|
for _, r := range c.Resources {
|
||||||
noun := &depgraph.Noun{
|
noun := &depgraph.Noun{
|
||||||
Name: r.Id(),
|
Name: r.Id(),
|
||||||
Meta: r,
|
Meta: &GraphNodeResource{
|
||||||
|
Type: r.Type,
|
||||||
|
Config: r,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
nouns[noun.Name] = noun
|
nouns[noun.Name] = noun
|
||||||
}
|
}
|
||||||
|
@ -77,7 +101,13 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
||||||
rs := s.Resources[k]
|
rs := s.Resources[k]
|
||||||
noun := &depgraph.Noun{
|
noun := &depgraph.Noun{
|
||||||
Name: k,
|
Name: k,
|
||||||
Meta: rs,
|
Meta: &GraphNodeResource{
|
||||||
|
Type: rs.Type,
|
||||||
|
Orphan: true,
|
||||||
|
Resource: &Resource{
|
||||||
|
State: rs,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
g.Nouns = append(g.Nouns, noun)
|
g.Nouns = append(g.Nouns, noun)
|
||||||
}
|
}
|
||||||
|
@ -89,18 +119,10 @@ func graphAddProviderConfigs(g *depgraph.Graph, c *config.Config) {
|
||||||
nounsList := make([]*depgraph.Noun, 0, 2)
|
nounsList := make([]*depgraph.Noun, 0, 2)
|
||||||
pcNouns := make(map[string]*depgraph.Noun)
|
pcNouns := make(map[string]*depgraph.Noun)
|
||||||
for _, noun := range g.Nouns {
|
for _, noun := range g.Nouns {
|
||||||
var rtype string
|
resourceNode := noun.Meta.(*GraphNodeResource)
|
||||||
switch m := noun.Meta.(type) {
|
|
||||||
case *config.Resource:
|
|
||||||
rtype = m.Type
|
|
||||||
case *ResourceState:
|
|
||||||
rtype = m.Type
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the provider config for this resource
|
// Look up the provider config for this resource
|
||||||
pcName := config.ProviderConfigName(rtype, c.ProviderConfigs)
|
pcName := config.ProviderConfigName(resourceNode.Type, c.ProviderConfigs)
|
||||||
if pcName == "" {
|
if pcName == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -110,12 +132,20 @@ func graphAddProviderConfigs(g *depgraph.Graph, c *config.Config) {
|
||||||
if !ok {
|
if !ok {
|
||||||
pcNoun = &depgraph.Noun{
|
pcNoun = &depgraph.Noun{
|
||||||
Name: fmt.Sprintf("provider.%s", pcName),
|
Name: fmt.Sprintf("provider.%s", pcName),
|
||||||
Meta: c.ProviderConfigs[pcName],
|
Meta: &GraphNodeResourceProvider{
|
||||||
|
ID: pcName,
|
||||||
|
Config: c.ProviderConfigs[pcName],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
pcNouns[pcName] = pcNoun
|
pcNouns[pcName] = pcNoun
|
||||||
nounsList = append(nounsList, pcNoun)
|
nounsList = append(nounsList, pcNoun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the resource provider ID for this noun so we can look it
|
||||||
|
// up later easily.
|
||||||
|
resourceNode.ResourceProviderID = pcName
|
||||||
|
|
||||||
|
// Add the provider configuration noun as a dependency
|
||||||
dep := &depgraph.Dependency{
|
dep := &depgraph.Dependency{
|
||||||
Name: pcName,
|
Name: pcName,
|
||||||
Source: noun,
|
Source: noun,
|
||||||
|
@ -148,10 +178,12 @@ func graphAddVariableDeps(g *depgraph.Graph) {
|
||||||
for _, n := range g.Nouns {
|
for _, n := range g.Nouns {
|
||||||
var vars map[string]config.InterpolatedVariable
|
var vars map[string]config.InterpolatedVariable
|
||||||
switch m := n.Meta.(type) {
|
switch m := n.Meta.(type) {
|
||||||
case *config.Resource:
|
case *GraphNodeResource:
|
||||||
vars = m.RawConfig.Variables
|
if !m.Orphan {
|
||||||
case *config.ProviderConfig:
|
vars = m.Config.RawConfig.Variables
|
||||||
vars = m.RawConfig.Variables
|
}
|
||||||
|
case *GraphNodeResourceProvider:
|
||||||
|
vars = m.Config.RawConfig.Variables
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,13 +78,6 @@ func New(c *Config) (*Terraform, error) {
|
||||||
errs = append(errs, tpErrs...)
|
errs = append(errs, tpErrs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the resource graph
|
|
||||||
graph := c.Config.Graph()
|
|
||||||
if err := graph.Validate(); err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf(
|
|
||||||
"Resource graph has an error: %s", err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we accumulated any errors, then return them all
|
// If we accumulated any errors, then return them all
|
||||||
|
@ -100,13 +93,13 @@ func New(c *Config) (*Terraform, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terraform) Apply(p *Plan) (*State, error) {
|
func (t *Terraform) Apply(p *Plan) (*State, error) {
|
||||||
graph := t.config.Graph()
|
graph, err := t.Graph(p.Config, p.State)
|
||||||
if err := graph.Validate(); err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Graph invalid after prior validation: %s", err))
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := new(State)
|
result := new(State)
|
||||||
err := graph.Walk(t.applyWalkFn(p, result))
|
err = graph.Walk(t.applyWalkFn(p, result))
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,22 +109,27 @@ func (t *Terraform) Apply(p *Plan) (*State, error) {
|
||||||
// The resulting graph may have more resources than the configuration, because
|
// The resulting graph may have more resources than the configuration, because
|
||||||
// it can contain resources in the state file that need to be modified.
|
// it can contain resources in the state file that need to be modified.
|
||||||
func (t *Terraform) Graph(c *config.Config, s *State) (*depgraph.Graph, error) {
|
func (t *Terraform) Graph(c *config.Config, s *State) (*depgraph.Graph, error) {
|
||||||
|
// Get the basic graph with the raw metadata
|
||||||
g := Graph(c, s)
|
g := Graph(c, s)
|
||||||
if err := g.Validate(); err != nil {
|
if err := g.Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next, we want to go through the graph and make sure that we
|
||||||
|
// map a provider to each of the resources.
|
||||||
|
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terraform) Plan(s *State) (*Plan, error) {
|
func (t *Terraform) Plan(s *State) (*Plan, error) {
|
||||||
graph := t.config.Graph()
|
// TODO: add config param
|
||||||
if err := graph.Validate(); err != nil {
|
graph, err := t.Graph(nil, s)
|
||||||
panic(fmt.Sprintf("Graph invalid after prior validation: %s", err))
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := new(Plan)
|
result := new(Plan)
|
||||||
err := graph.Walk(t.planWalkFn(s, result))
|
err = graph.Walk(t.planWalkFn(s, result))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue