terraform: add some semantic check functions

This commit is contained in:
Mitchell Hashimoto 2014-07-02 20:47:10 -07:00
parent d0577fda02
commit c8c7d6baa3
3 changed files with 34 additions and 129 deletions

View File

@ -1,147 +1,24 @@
package terraform package terraform
/*
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
) )
/* // smcUserVariables does all the semantic checks to verify that the
// smcProviders matches up the resources with a provider and initializes // variables given satisfy the configuration itself.
// it. This does not call "Configure" on the ResourceProvider, since that func smcUserVariables(c *config.Config, vs map[string]string) []error {
// might actually depend on upstream resources.
func smcProviders(
c *Config) (map[*config.Resource]*terraformProvider, []error) {
var errs []error
// Keep track of providers we know we couldn't instantiate so
// that we don't get a ton of errors about the same provider.
failures := make(map[string]struct{})
// Go through each resource and match it up to a provider
mapping := make(map[*config.Resource]*terraformProvider)
providers := make(map[string]ResourceProvider)
tpcache := make(map[string]*terraformProvider)
ResourceLoop:
for _, r := range c.Config.Resources {
// Find the prefixes that match this in the order of
// longest matching first (most specific)
prefixes := matchingPrefixes(r.Type, c.Providers)
if len(prefixes) > 0 {
if _, ok := failures[prefixes[0]]; ok {
// We already failed this provider, meaning this
// resource will never succeed, so just continue.
continue
}
}
// Go through each prefix and instantiate if necessary, then
// verify if this provider is of use to us or not.
var providerName string
var provider ResourceProvider
for _, prefix := range prefixes {
// Initialize the provider
p, ok := providers[prefix]
if !ok {
var err error
p, err = c.Providers[prefix]()
if err != nil {
errs = append(errs, fmt.Errorf(
"Error instantiating resource provider for "+
"prefix %s: %s", prefix, err))
// Record the error so that we don't check it again
failures[prefix] = struct{}{}
// Jump to the next resource
continue ResourceLoop
}
providers[prefix] = p
}
// Test if this provider matches what we need
if !ProviderSatisfies(p, r.Type) {
continue
}
providerName = prefix
provider = p
break
}
// If we didn't find a valid provider, then error and continue
if providerName == "" {
errs = append(errs, fmt.Errorf(
"Provider for resource %s not found.",
r.Id()))
continue
}
// Find the matching provider configuration for this resource
var pc *config.ProviderConfig
pcName := config.ProviderConfigName(r.Type, c.Config.ProviderConfigs)
if pcName != "" {
pc = c.Config.ProviderConfigs[pcName]
}
// Look up if we already have a provider for this pair of PC
// and provider name. If not, create it.
cacheKey := fmt.Sprintf("%s|%s", pcName, providerName)
tp, ok := tpcache[cacheKey]
if !ok {
renew := false
for _, tp := range tpcache {
if tp.Provider == provider {
renew = true
break
}
}
if renew {
var err error
provider, err = c.Providers[providerName]()
if err != nil {
errs = append(errs, fmt.Errorf(
"Error instantiating resource provider for "+
"prefix %s: %s", providerName, err))
continue
}
}
tp = &terraformProvider{
Provider: provider,
Config: pc,
}
tpcache[cacheKey] = tp
}
mapping[r] = tp
}
if len(errs) > 0 {
return nil, errs
}
return mapping, nil
}
// smcVariables does all the semantic checks to verify that the
// variables given in the configuration to instantiate a Terraform
// struct are valid.
func smcVariables(c *Config) []error {
var errs []error var errs []error
// Check that all required variables are present // Check that all required variables are present
required := make(map[string]struct{}) required := make(map[string]struct{})
for k, v := range c.Config.Variables { for k, v := range c.Variables {
if v.Required() { if v.Required() {
required[k] = struct{}{} required[k] = struct{}{}
} }
} }
for k, _ := range c.Variables { for k, _ := range vs {
delete(required, k) delete(required, k)
} }
if len(required) > 0 { if len(required) > 0 {
@ -155,4 +32,3 @@ func smcVariables(c *Config) []error {
return errs return errs
} }
*/

View File

@ -0,0 +1,21 @@
package terraform
import (
"testing"
)
func TestSMCUserVariables(t *testing.T) {
c := testConfig(t, "smc-uservars")
// Required variables not set
errs := smcUserVariables(c, nil)
if len(errs) == 0 {
t.Fatal("should have errors")
}
// Required variables set, optional variables unset
errs = smcUserVariables(c, map[string]string{"foo": "bar"})
if len(errs) != 0 {
t.Fatalf("err: %#v", errs)
}
}

View File

@ -0,0 +1,8 @@
# Required
variable "foo" {
}
# Optional
variable "bar" {
default = "baz"
}