mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
terraform: fill in the graph with the providers
This commit is contained in:
parent
cdab89d7c1
commit
9d4f7b71c4
@ -2,6 +2,7 @@ package terraform
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
@ -24,9 +25,10 @@ type GraphNodeResource struct {
|
|||||||
// GraphNodeResourceProvider is a node type in the graph that represents
|
// GraphNodeResourceProvider is a node type in the graph that represents
|
||||||
// the configuration for a resource provider.
|
// the configuration for a resource provider.
|
||||||
type GraphNodeResourceProvider struct {
|
type GraphNodeResourceProvider struct {
|
||||||
ID string
|
ID string
|
||||||
Providers []ResourceProvider
|
Providers map[string]ResourceProvider
|
||||||
Config *config.ProviderConfig
|
ProviderKeys []string
|
||||||
|
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.
|
||||||
@ -71,6 +73,25 @@ func Graph(c *config.Config, s *State) *depgraph.Graph {
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GraphFull(g *depgraph.Graph, ps map[string]ResourceProviderFactory) error {
|
||||||
|
// Add missing providers from the mapping
|
||||||
|
if err := graphAddMissingResourceProviders(g, ps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all the providers
|
||||||
|
if err := graphInitResourceProviders(g, ps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the providers to resources
|
||||||
|
if err := graphMapResourceProviders(g); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// configGraph turns a configuration structure into a dependency graph.
|
// configGraph turns a configuration structure into a dependency graph.
|
||||||
func graphAddConfigResources(g *depgraph.Graph, c *config.Config) {
|
func graphAddConfigResources(g *depgraph.Graph, c *config.Config) {
|
||||||
// This tracks all the resource nouns
|
// This tracks all the resource nouns
|
||||||
@ -97,6 +118,65 @@ func graphAddConfigResources(g *depgraph.Graph, c *config.Config) {
|
|||||||
g.Nouns = append(g.Nouns, nounsList...)
|
g.Nouns = append(g.Nouns, nounsList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// graphAddMissingResourceProviders adds GraphNodeResourceProvider nodes for
|
||||||
|
// the resources that do not have an explicit resource provider specified
|
||||||
|
// because no provider configuration was given.
|
||||||
|
func graphAddMissingResourceProviders(
|
||||||
|
g *depgraph.Graph,
|
||||||
|
ps map[string]ResourceProviderFactory) error {
|
||||||
|
var errs []error
|
||||||
|
|
||||||
|
for _, n := range g.Nouns {
|
||||||
|
rn, ok := n.Meta.(*GraphNodeResource)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rn.ResourceProviderID != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixes := matchingPrefixes(rn.Type, ps)
|
||||||
|
if len(prefixes) == 0 {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"No matching provider for type: %s",
|
||||||
|
rn.Type))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The resource provider ID is simply the shortest matching
|
||||||
|
// prefix, since that'll give us the most resource providers
|
||||||
|
// to choose from.
|
||||||
|
rn.ResourceProviderID = prefixes[len(prefixes)-1]
|
||||||
|
|
||||||
|
// If we don't have a matching noun for this yet, insert it.
|
||||||
|
pn := g.Noun(fmt.Sprintf("provider.%s", rn.ResourceProviderID))
|
||||||
|
if pn == nil {
|
||||||
|
pn = &depgraph.Noun{
|
||||||
|
Name: fmt.Sprintf("provider.%s", rn.ResourceProviderID),
|
||||||
|
Meta: &GraphNodeResourceProvider{
|
||||||
|
ID: rn.ResourceProviderID,
|
||||||
|
Config: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Nouns = append(g.Nouns, pn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the provider configuration noun as a dependency
|
||||||
|
dep := &depgraph.Dependency{
|
||||||
|
Name: pn.Name,
|
||||||
|
Source: n,
|
||||||
|
Target: pn,
|
||||||
|
}
|
||||||
|
n.Deps = append(n.Deps, dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return &MultiError{Errors: errs}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// graphAddOrphans adds the orphans to the graph.
|
// graphAddOrphans adds the orphans to the graph.
|
||||||
func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
||||||
for _, k := range s.Orphans(c) {
|
for _, k := range s.Orphans(c) {
|
||||||
@ -249,6 +329,8 @@ func graphInitResourceProviders(
|
|||||||
|
|
||||||
// Go through each prefix and instantiate if necessary, then
|
// Go through each prefix and instantiate if necessary, then
|
||||||
// verify if this provider is of use to us or not.
|
// verify if this provider is of use to us or not.
|
||||||
|
rn.Providers = make(map[string]ResourceProvider)
|
||||||
|
rn.ProviderKeys = prefixes
|
||||||
for _, prefix := range prefixes {
|
for _, prefix := range prefixes {
|
||||||
p, err := ps[prefix]()
|
p, err := ps[prefix]()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -263,7 +345,7 @@ func graphInitResourceProviders(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rn.Providers = append(rn.Providers, p)
|
rn.Providers[prefix] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we never found a provider, then error and continue
|
// If we never found a provider, then error and continue
|
||||||
@ -317,7 +399,13 @@ func graphMapResourceProviders(g *depgraph.Graph) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var provider ResourceProvider
|
var provider ResourceProvider
|
||||||
for _, rp := range rpn.Providers {
|
for _, k := range rpn.ProviderKeys {
|
||||||
|
// Only try this provider if it has the right prefix
|
||||||
|
if !strings.HasPrefix(rn.Type, k) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rp := rpn.Providers[k]
|
||||||
if ProviderSatisfies(rp, rn.Type) {
|
if ProviderSatisfies(rp, rn.Type) {
|
||||||
provider = rp
|
provider = rp
|
||||||
break
|
break
|
||||||
@ -356,7 +444,24 @@ func matchingPrefixes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mitchellh): Order by longest prefix first
|
// Sort by longest first
|
||||||
|
sort.Sort(stringLenSort(result))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stringLenSort implements sort.Interface and sorts strings in increasing
|
||||||
|
// length order. i.e. "a", "aa", "aaa"
|
||||||
|
type stringLenSort []string
|
||||||
|
|
||||||
|
func (s stringLenSort) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stringLenSort) Less(i, j int) bool {
|
||||||
|
return len(s[i]) < len(s[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stringLenSort) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
@ -112,13 +112,8 @@ func (t *Terraform) Graph(c *config.Config, s *State) (*depgraph.Graph, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all the providers
|
// Fill the graph with the providers
|
||||||
if err := graphInitResourceProviders(g, t.providers); err != nil {
|
if err := GraphFull(g, t.providers); err != nil {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map the providers to resources
|
|
||||||
if err := graphMapResourceProviders(g); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ provider "aws" {
|
|||||||
foo = "${openstack_floating_ip.random.value}"
|
foo = "${openstack_floating_ip.random.value}"
|
||||||
}
|
}
|
||||||
|
|
||||||
#resource "openstack_floating_ip" "random" {}
|
resource "openstack_floating_ip" "random" {}
|
||||||
|
|
||||||
resource "aws_security_group" "firewall" {}
|
resource "aws_security_group" "firewall" {}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user