config: "ResourceMode" concept for resources

Previously resources were assumed to always support the full set of
create, read, update and delete operations, and Terraform's resource
management lifecycle.

Data sources introduce a new kind of resource that only supports the
"read" operation. To support this, a new "Mode" field is added to
the Resource concept within the config layer, which can be set to
ManagedResourceMode (to indicate the only mode previously possible) or
DataResourceMode (to indicate that only "read" is supported).

To support both managed and data resources in the tests, the
stringification of resources in config_string.go is adjusted slightly
to use the Id() method rather than the unusual type[name] serialization
from before, causing a simple mechanical adjustment to the loader tests'
expected result strings.
This commit is contained in:
Martin Atkins 2016-05-01 14:43:05 -07:00
parent f331240601
commit fc4fa10981
6 changed files with 68 additions and 32 deletions

View File

@ -67,9 +67,11 @@ type ProviderConfig struct {
}
// A resource represents a single Terraform resource in the configuration.
// A Terraform resource is something that represents some component that
// can be created and managed, and has some properties associated with it.
// A Terraform resource is something that supports some or all of the
// usual "create, read, update, delete" operations, depending on
// the given Mode.
type Resource struct {
Mode ResourceMode // which operations the resource supports
Name string
Type string
RawCount *RawConfig
@ -85,6 +87,7 @@ type Resource struct {
// interpolation.
func (r *Resource) Copy() *Resource {
n := &Resource{
Mode: r.Mode,
Name: r.Name,
Type: r.Type,
RawCount: r.RawCount.Copy(),
@ -210,7 +213,14 @@ func (r *Resource) Count() (int, error) {
// A unique identifier for this resource.
func (r *Resource) Id() string {
return fmt.Sprintf("%s.%s", r.Type, r.Name)
switch r.Mode {
case ManagedResourceMode:
return fmt.Sprintf("%s.%s", r.Type, r.Name)
case DataResourceMode:
return fmt.Sprintf("data.%s.%s", r.Type, r.Name)
default:
panic(fmt.Errorf("unknown resource mode %s", r.Mode))
}
}
// Validate does some basic semantic checking of the configuration.
@ -804,13 +814,14 @@ func (c *ProviderConfig) mergerMerge(m merger) merger {
}
func (r *Resource) mergerName() string {
return fmt.Sprintf("%s.%s", r.Type, r.Name)
return r.Id()
}
func (r *Resource) mergerMerge(m merger) merger {
r2 := m.(*Resource)
result := *r
result.Mode = r2.Mode
result.Name = r2.Name
result.Type = r2.Type
result.RawConfig = result.RawConfig.merge(r2.RawConfig)

View File

@ -178,7 +178,7 @@ func resourcesStr(rs []*Resource) string {
ks := make([]string, 0, len(rs))
mapping := make(map[string]int)
for i, r := range rs {
k := fmt.Sprintf("%s[%s]", r.Type, r.Name)
k := r.Id()
ks = append(ks, k)
mapping[k] = i
}
@ -190,9 +190,8 @@ func resourcesStr(rs []*Resource) string {
for _, i := range order {
r := rs[i]
result += fmt.Sprintf(
"%s[%s] (x%s)\n",
r.Type,
r.Name,
"%s (x%s)\n",
r.Id(),
r.RawCount.Value())
ks := make([]string, 0, len(r.RawConfig.Raw))

View File

@ -566,6 +566,7 @@ func loadResourcesHcl(list *ast.ObjectList) ([]*Resource, error) {
}
result = append(result, &Resource{
Mode: ManagedResourceMode,
Name: k,
Type: t,
RawCount: countConfig,

View File

@ -742,13 +742,13 @@ func TestLoad_jsonAttributes(t *testing.T) {
}
const jsonAttributeStr = `
cloudstack_firewall[test] (x1)
cloudstack_firewall.test (x1)
ipaddress
rule
`
const windowsHeredocResourcesStr = `
aws_instance[test] (x1)
aws_instance.test (x1)
user_data
`
@ -759,17 +759,17 @@ aws
`
const heredocResourcesStr = `
aws_iam_policy[policy] (x1)
aws_iam_policy.policy (x1)
description
name
path
policy
aws_instance[heredocwithnumbers] (x1)
aws_instance.heredocwithnumbers (x1)
ami
provisioners
local-exec
command
aws_instance[test] (x1)
aws_instance.test (x1)
ami
provisioners
remote-exec
@ -777,7 +777,7 @@ aws_instance[test] (x1)
`
const escapedquotesResourcesStr = `
aws_instance[quotes] (x1)
aws_instance.quotes (x1)
ami
vars
user: var.ami
@ -800,7 +800,7 @@ do
`
const basicResourcesStr = `
aws_instance[db] (x1)
aws_instance.db (x1)
VPC
security_groups
provisioners
@ -811,7 +811,7 @@ aws_instance[db] (x1)
aws_instance.web
vars
resource: aws_security_group.firewall.*.id
aws_instance[web] (x1)
aws_instance.web (x1)
ami
network_interface
security_groups
@ -822,7 +822,7 @@ aws_instance[web] (x1)
vars
resource: aws_security_group.firewall.foo
user: var.foo
aws_security_group[firewall] (x5)
aws_security_group.firewall (x5)
`
const basicVariablesStr = `
@ -854,18 +854,18 @@ do
`
const dirBasicResourcesStr = `
aws_instance[db] (x1)
aws_instance.db (x1)
security_groups
vars
resource: aws_security_group.firewall.*.id
aws_instance[web] (x1)
aws_instance.web (x1)
ami
network_interface
security_groups
vars
resource: aws_security_group.firewall.foo
user: var.foo
aws_security_group[firewall] (x5)
aws_security_group.firewall (x5)
`
const dirBasicVariablesStr = `
@ -891,10 +891,10 @@ do
`
const dirOverrideResourcesStr = `
aws_instance[db] (x1)
aws_instance.db (x1)
ami
security_groups
aws_instance[web] (x1)
aws_instance.web (x1)
ami
foo
network_interface
@ -902,7 +902,7 @@ aws_instance[web] (x1)
vars
resource: aws_security_group.firewall.foo
user: var.foo
aws_security_group[firewall] (x5)
aws_security_group.firewall (x5)
`
const dirOverrideVariablesStr = `
@ -918,8 +918,8 @@ aws
`
const importResourcesStr = `
aws_security_group[db] (x1)
aws_security_group[web] (x1)
aws_security_group.db (x1)
aws_security_group.web (x1)
`
const importVariablesStr = `
@ -938,7 +938,7 @@ bar
`
const provisionerResourcesStr = `
aws_instance[web] (x1)
aws_instance.web (x1)
ami
security_groups
provisioners
@ -950,7 +950,7 @@ aws_instance[web] (x1)
`
const connectionResourcesStr = `
aws_instance[web] (x1)
aws_instance.web (x1)
ami
security_groups
provisioners
@ -976,17 +976,17 @@ foo (required)
`
const createBeforeDestroyResourcesStr = `
aws_instance[bar] (x1)
aws_instance.bar (x1)
ami
aws_instance[web] (x1)
aws_instance.web (x1)
ami
`
const ignoreChangesResourcesStr = `
aws_instance[bar] (x1)
aws_instance.bar (x1)
ami
aws_instance[baz] (x1)
aws_instance.baz (x1)
ami
aws_instance[web] (x1)
aws_instance.web (x1)
ami
`

9
config/resource_mode.go Normal file
View File

@ -0,0 +1,9 @@
package config
//go:generate stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go
type ResourceMode int
const (
ManagedResourceMode ResourceMode = iota
DataResourceMode
)

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT
package config
import "fmt"
const _ResourceMode_name = "ManagedResourceModeDataResourceMode"
var _ResourceMode_index = [...]uint8{0, 19, 35}
func (i ResourceMode) String() string {
if i < 0 || i >= ResourceMode(len(_ResourceMode_index)-1) {
return fmt.Sprintf("ResourceMode(%d)", i)
}
return _ResourceMode_name[_ResourceMode_index[i]:_ResourceMode_index[i+1]]
}