mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
terraform: provider inheritence is functional
This commit is contained in:
parent
8dbc7e0ccb
commit
1f1563c95b
@ -913,6 +913,37 @@ func (c *walkContext) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
|
|||||||
raw = sharedProvider.Config.RawConfig
|
raw = sharedProvider.Config.RawConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have a parent, then merge in the parent configurations
|
||||||
|
// properly so we "inherit" the configurations.
|
||||||
|
if sharedProvider.Parent != nil {
|
||||||
|
var rawMap map[string]interface{}
|
||||||
|
if raw != nil {
|
||||||
|
rawMap = raw.Raw
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := sharedProvider.Parent
|
||||||
|
for parent != nil {
|
||||||
|
if parent.Config != nil {
|
||||||
|
if rawMap == nil {
|
||||||
|
rawMap = parent.Config.RawConfig.Raw
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range parent.Config.RawConfig.Config() {
|
||||||
|
rawMap[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update our configuration to be the merged result
|
||||||
|
var err error
|
||||||
|
raw, err = config.NewRawConfig(rawMap)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error merging configurations: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc := NewResourceConfig(raw)
|
rc := NewResourceConfig(raw)
|
||||||
rc.interpolate(c)
|
rc.interpolate(c)
|
||||||
|
|
||||||
|
@ -1592,10 +1592,7 @@ func TestContextPlan_moduleOrphans(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestContextPlan_moduleProviderInherit(t *testing.T) {
|
func TestContextPlan_moduleProviderInherit(t *testing.T) {
|
||||||
t.Skip()
|
|
||||||
|
|
||||||
var l sync.Mutex
|
var l sync.Mutex
|
||||||
var ps []*MockResourceProvider
|
|
||||||
var calls []string
|
var calls []string
|
||||||
|
|
||||||
m := testModule(t, "plan-module-provider-inherit")
|
m := testModule(t, "plan-module-provider-inherit")
|
||||||
@ -1622,7 +1619,6 @@ func TestContextPlan_moduleProviderInherit(t *testing.T) {
|
|||||||
calls = append(calls, v.(string))
|
calls = append(calls, v.(string))
|
||||||
return testDiffFn(info, state, c)
|
return testDiffFn(info, state, c)
|
||||||
}
|
}
|
||||||
ps = append(ps, p)
|
|
||||||
return p, nil
|
return p, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1633,10 +1629,6 @@ func TestContextPlan_moduleProviderInherit(t *testing.T) {
|
|||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ps) != 2 {
|
|
||||||
t.Fatalf("bad: %#v", ps)
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := calls
|
actual := calls
|
||||||
sort.Strings(actual)
|
sort.Strings(actual)
|
||||||
expected := []string{"child", "root"}
|
expected := []string{"child", "root"}
|
||||||
|
@ -68,6 +68,9 @@ type GraphOpts struct {
|
|||||||
// 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"
|
||||||
|
|
||||||
|
// GraphMeta is the metadata attached to the graph itself.
|
||||||
|
type GraphMeta struct{}
|
||||||
|
|
||||||
// GraphNodeModule is a node type in the graph that represents a module
|
// GraphNodeModule is a node type in the graph that represents a module
|
||||||
// that will be created/managed.
|
// that will be created/managed.
|
||||||
type GraphNodeModule struct {
|
type GraphNodeModule struct {
|
||||||
@ -111,6 +114,9 @@ type graphSharedProvider struct {
|
|||||||
Config *config.ProviderConfig
|
Config *config.ProviderConfig
|
||||||
Providers map[string]ResourceProvider
|
Providers map[string]ResourceProvider
|
||||||
ProviderKeys []string
|
ProviderKeys []string
|
||||||
|
Parent *graphSharedProvider
|
||||||
|
|
||||||
|
parentNoun *depgraph.Noun
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graph builds a dependency graph of all the resources for infrastructure
|
// Graph builds a dependency graph of all the resources for infrastructure
|
||||||
@ -165,6 +171,7 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) {
|
|||||||
log.Printf("[DEBUG] Creating graph for path: %v", opts.ModulePath)
|
log.Printf("[DEBUG] Creating graph for path: %v", opts.ModulePath)
|
||||||
|
|
||||||
g := new(depgraph.Graph)
|
g := new(depgraph.Graph)
|
||||||
|
g.Meta = new(GraphMeta)
|
||||||
|
|
||||||
// First, build the initial resource graph. This only has the resources
|
// First, build the initial resource graph. This only has the resources
|
||||||
// and no dependencies. This only adds resources that are in the config
|
// and no dependencies. This only adds resources that are in the config
|
||||||
@ -791,6 +798,42 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, mod *ModuleState) {
|
|||||||
// graphAddParentProviderConfigs goes through and adds/merges provider
|
// graphAddParentProviderConfigs goes through and adds/merges provider
|
||||||
// configurations from the parent.
|
// configurations from the parent.
|
||||||
func graphAddParentProviderConfigs(g, parent *depgraph.Graph) {
|
func graphAddParentProviderConfigs(g, parent *depgraph.Graph) {
|
||||||
|
var nounsList []*depgraph.Noun
|
||||||
|
for _, n := range parent.Nouns {
|
||||||
|
pn, ok := n.Meta.(*GraphNodeResourceProvider)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a provider configuration with the exact same
|
||||||
|
// name, then set specify the parent pointer to their shared
|
||||||
|
// config.
|
||||||
|
ourProviderRaw := g.Noun(n.Name)
|
||||||
|
|
||||||
|
// If we don't have a matching configuration, then create one.
|
||||||
|
if ourProviderRaw == nil {
|
||||||
|
noun := &depgraph.Noun{
|
||||||
|
Name: n.Name,
|
||||||
|
Meta: &GraphNodeResourceProvider{
|
||||||
|
ID: pn.ID,
|
||||||
|
Provider: &graphSharedProvider{
|
||||||
|
Parent: pn.Provider,
|
||||||
|
parentNoun: n,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nounsList = append(nounsList, noun)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a matching configuration, then set the parent pointer
|
||||||
|
ourProvider := ourProviderRaw.Meta.(*GraphNodeResourceProvider)
|
||||||
|
ourProvider.Provider.Parent = pn.Provider
|
||||||
|
ourProvider.Provider.parentNoun = n
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Nouns = append(g.Nouns, nounsList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// graphAddConfigProviderConfigs adds a GraphNodeResourceProvider for every
|
// graphAddConfigProviderConfigs adds a GraphNodeResourceProvider for every
|
||||||
@ -1093,6 +1136,26 @@ func graphInitResourceProviders(
|
|||||||
func graphAddResourceProviderDeps(g *depgraph.Graph) {
|
func graphAddResourceProviderDeps(g *depgraph.Graph) {
|
||||||
for _, rawN := range g.Nouns {
|
for _, rawN := range g.Nouns {
|
||||||
switch n := rawN.Meta.(type) {
|
switch n := rawN.Meta.(type) {
|
||||||
|
case *GraphNodeModule:
|
||||||
|
// Check if the module depends on any of our providers
|
||||||
|
// by seeing if there is a parent node back.
|
||||||
|
for _, moduleRaw := range n.Graph.Nouns {
|
||||||
|
pn, ok := moduleRaw.Meta.(*GraphNodeResourceProvider)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pn.Provider.parentNoun == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the dependency to the provider
|
||||||
|
dep := &depgraph.Dependency{
|
||||||
|
Name: pn.Provider.parentNoun.Name,
|
||||||
|
Source: rawN,
|
||||||
|
Target: pn.Provider.parentNoun,
|
||||||
|
}
|
||||||
|
rawN.Deps = append(rawN.Deps, dep)
|
||||||
|
}
|
||||||
case *GraphNodeResource:
|
case *GraphNodeResource:
|
||||||
// Not sure how this would happen, but we might as well
|
// Not sure how this would happen, but we might as well
|
||||||
// check for it.
|
// check for it.
|
||||||
|
@ -868,6 +868,7 @@ aws_security_group.firewall
|
|||||||
aws_security_group.firewall -> provider.aws
|
aws_security_group.firewall -> provider.aws
|
||||||
module.consul
|
module.consul
|
||||||
module.consul -> aws_security_group.firewall
|
module.consul -> aws_security_group.firewall
|
||||||
|
module.consul -> provider.aws
|
||||||
provider.aws
|
provider.aws
|
||||||
root
|
root
|
||||||
root -> aws_instance.web
|
root -> aws_instance.web
|
||||||
@ -878,6 +879,8 @@ root
|
|||||||
const testTerraformGraphModulesConsulStr = `
|
const testTerraformGraphModulesConsulStr = `
|
||||||
root: root
|
root: root
|
||||||
aws_instance.server
|
aws_instance.server
|
||||||
|
aws_instance.server -> provider.aws
|
||||||
|
provider.aws
|
||||||
root
|
root
|
||||||
root -> aws_instance.server
|
root -> aws_instance.server
|
||||||
`
|
`
|
||||||
@ -890,6 +893,7 @@ aws_instance.web
|
|||||||
aws_security_group.firewall
|
aws_security_group.firewall
|
||||||
aws_security_group.firewall -> provider.aws
|
aws_security_group.firewall -> provider.aws
|
||||||
module.consul
|
module.consul
|
||||||
|
module.consul -> provider.aws
|
||||||
provider.aws
|
provider.aws
|
||||||
root
|
root
|
||||||
root -> aws_instance.web
|
root -> aws_instance.web
|
||||||
@ -900,6 +904,8 @@ root
|
|||||||
const testTerraformGraphModuleOrphanConsulStr = `
|
const testTerraformGraphModuleOrphanConsulStr = `
|
||||||
root: root
|
root: root
|
||||||
aws_instance.old
|
aws_instance.old
|
||||||
|
aws_instance.old -> provider.aws
|
||||||
|
provider.aws
|
||||||
root
|
root
|
||||||
root -> aws_instance.old
|
root -> aws_instance.old
|
||||||
`
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user