From 847cd7ac515f1115c1a5efb06971504a1c0fa01b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 17 Jun 2014 19:06:13 -0700 Subject: [PATCH] diff: lazy resource map --- builtin/providers/aws/resource_provider.go | 14 +++++ diff/lazy_resource_map.go | 51 +++++++++++++++++++ diff/lazy_resource_map_test.go | 45 ++++++++++++++++ diff/{builder.go => resource_builder.go} | 14 ----- ...ilder_test.go => resource_builder_test.go} | 0 5 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 diff/lazy_resource_map.go create mode 100644 diff/lazy_resource_map_test.go rename diff/{builder.go => resource_builder.go} (78%) rename diff/{builder_test.go => resource_builder_test.go} (100%) diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index 465fb2e3d..00da3b37f 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -23,6 +23,20 @@ func (p *ResourceProvider) Configure(*terraform.ResourceConfig) error { func (p *ResourceProvider) Diff( s *terraform.ResourceState, c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + diffMap.CreateAttrs([]string{ + "ami", + "availability_zone", + "instance_type", + "region", + }) + diffMap.CreateComputedAttrs([]string{ + "id", + "public_dns", + "public_ip", + "private_dns", + "private_ip", + }) + return &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "id": &terraform.ResourceAttrDiff{ diff --git a/diff/lazy_resource_map.go b/diff/lazy_resource_map.go new file mode 100644 index 000000000..4039c0570 --- /dev/null +++ b/diff/lazy_resource_map.go @@ -0,0 +1,51 @@ +package diff + +import ( + "sync" +) + +// LazyResourceMap is a way to lazy-load resource builders. +// +// By lazy loading resource builders, a considerable amount of compute +// effort for building the builders can be avoided. This is especially +// helpful in Terraform providers that support many resource types. +type LazyResourceMap struct { + Resources map[string]ResourceBuilderFactory + + l sync.Mutex + memoized map[string]*ResourceBuilder +} + +// ResourceBuilderFactory is a factory function for creating a resource +// builder that is used for lazy loading resource builders in the Builder +// struct. +type ResourceBuilderFactory func() *ResourceBuilder + +// Get gets the ResourceBuilder for the given resource type, and returns +// nil if the resource builder cannot be found. +// +// This will memoize the result, returning the same result for the same +// type if called again. +func (m *LazyResourceMap) Get(r string) *ResourceBuilder { + m.l.Lock() + defer m.l.Unlock() + + // If we have it saved, return that + if rb, ok := m.memoized[r]; ok { + return rb + } + + // Get the factory function + f, ok := m.Resources[r] + if !ok { + return nil + } + + // Save it so that we don't rebuild + if m.memoized == nil { + m.memoized = make(map[string]*ResourceBuilder) + } + m.memoized[r] = f() + + return m.memoized[r] +} diff --git a/diff/lazy_resource_map_test.go b/diff/lazy_resource_map_test.go new file mode 100644 index 000000000..53568123f --- /dev/null +++ b/diff/lazy_resource_map_test.go @@ -0,0 +1,45 @@ +package diff + +import ( + "testing" +) + +func TestLazyResourceMap(t *testing.T) { + rb1 := new(ResourceBuilder) + rb2 := new(ResourceBuilder) + + rm := &LazyResourceMap{ + Resources: map[string]ResourceBuilderFactory{ + "foo": testRBFactory(rb1), + "bar": testRBFactory(rb2), + "diff": func() *ResourceBuilder { + return new(ResourceBuilder) + }, + }, + } + + actual := rm.Get("foo") + if actual == nil { + t.Fatal("should not be nil") + } + if actual != rb1 { + t.Fatalf("bad: %p %p", rb1, actual) + } + if actual == rm.Get("bar") { + t.Fatalf("bad: %p %p", actual, rm.Get("bar")) + } + + actual = rm.Get("diff") + if actual == nil { + t.Fatal("should not be nil") + } + if actual != rm.Get("diff") { + t.Fatal("should memoize") + } +} + +func testRBFactory(rb *ResourceBuilder) ResourceBuilderFactory { + return func() *ResourceBuilder { + return rb + } +} diff --git a/diff/builder.go b/diff/resource_builder.go similarity index 78% rename from diff/builder.go rename to diff/resource_builder.go index 97a56dd58..7852bad94 100644 --- a/diff/builder.go +++ b/diff/resource_builder.go @@ -1,18 +1,9 @@ -// The diff package provides high-level constructs for easily building -// and working with Terraform diff structures. package diff import ( "github.com/hashicorp/terraform/terraform" ) -// Builder is a helper that is able to build terraform.ResourceDiff -// structures, and should be used by providers instead of hand-building -// them which can be tedious and error-prone. -type Builder struct { - Resources map[string]*ResourceBuilder -} - // ResourceBuilder is a helper that can knows about how a single resource // changes and how those changes affect the diff. type ResourceBuilder struct { @@ -20,11 +11,6 @@ type ResourceBuilder struct { RequiresNewAttrs []string } -// ResourceBuilderFactory is a factory function for creating a resource -// builder that is used for lazy loading resource builders in the Builder -// struct. -type ResourceBuilderFactory func() *ResourceBuilder - // Diff returns the ResourceDiff for a resource given its state and // configuration. func (b *ResourceBuilder) Diff( diff --git a/diff/builder_test.go b/diff/resource_builder_test.go similarity index 100% rename from diff/builder_test.go rename to diff/resource_builder_test.go