From 543e70aab1570f90cbd16c41305952afe7e5215f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 23 Jun 2014 19:32:49 -0700 Subject: [PATCH] helper/resource: nice helper for resourceprovider impl --- builtin/providers/aws/refresh.go | 31 ---------- builtin/providers/aws/resource_provider.go | 30 +--------- builtin/providers/aws/resources.go | 66 +++++++++++++++++++++ helper/resource/map.go | 68 ++++++++++++++++++++++ helper/resource/resource.go | 30 ++++++++++ 5 files changed, 167 insertions(+), 58 deletions(-) delete mode 100644 builtin/providers/aws/refresh.go create mode 100644 builtin/providers/aws/resources.go create mode 100644 helper/resource/map.go create mode 100644 helper/resource/resource.go diff --git a/builtin/providers/aws/refresh.go b/builtin/providers/aws/refresh.go deleted file mode 100644 index 16d23bdbe..000000000 --- a/builtin/providers/aws/refresh.go +++ /dev/null @@ -1,31 +0,0 @@ -package aws - -import ( - "github.com/hashicorp/terraform/terraform" -) - -// RefreshFunc is a function that performs a refresh of a specific type -// of resource. -type RefreshFunc func( - *ResourceProvider, - *terraform.ResourceState) (*terraform.ResourceState, error) - -// refreshMap keeps track of all the resources that this provider -// can refresh. -var refreshMap map[string]RefreshFunc - -func init() { - refreshMap = map[string]RefreshFunc{ - "aws_instance": refresh_aws_instance, - } -} - -func refresh_aws_instance( - p *ResourceProvider, - s *terraform.ResourceState) (*terraform.ResourceState, error) { - if s.ID != "" { - panic("OH MY WOW") - } - - return s, nil -} diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index 7b11f1312..b66434231 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -54,16 +54,7 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { func (p *ResourceProvider) Apply( s *terraform.ResourceState, d *terraform.ResourceDiff) (*terraform.ResourceState, error) { - result := &terraform.ResourceState{ - ID: "foo", - } - result = result.MergeDiff(d) - result.Attributes["public_dns"] = "foo" - result.Attributes["public_ip"] = "foo" - result.Attributes["private_dns"] = "foo" - result.Attributes["private_ip"] = "foo" - - return result, nil + return resourceMap.Apply(s, d, p) } func (p *ResourceProvider) Diff( @@ -79,24 +70,9 @@ func (p *ResourceProvider) Diff( func (p *ResourceProvider) Refresh( s *terraform.ResourceState) (*terraform.ResourceState, error) { - // If there isn't an ID previously, then the thing didn't exist, - // so there is nothing to refresh. - if s.ID == "" { - return s, nil - } - - f, ok := refreshMap[s.Type] - if !ok { - return s, fmt.Errorf("Unknown resource type: %s", s.Type) - } - - return f(p, s) + return resourceMap.Refresh(s, p) } func (p *ResourceProvider) Resources() []terraform.ResourceType { - return []terraform.ResourceType{ - terraform.ResourceType{ - Name: "aws_instance", - }, - } + return resourceMap.Resources() } diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go new file mode 100644 index 000000000..d5530e1ac --- /dev/null +++ b/builtin/providers/aws/resources.go @@ -0,0 +1,66 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/ec2" +) + +var resourceMap *resource.Map + +func init() { + resourceMap = &resource.Map{ + Mapping: map[string]resource.Resource{ + "aws_instance": resource.Resource{ + Create: resource_aws_instance_create, + Refresh: resource_aws_instance_refresh, + }, + }, + } +} + +func resource_aws_instance_create( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + ec2conn := p.ec2conn + + runOpts := &ec2.RunInstances{ + ImageId: d.Attributes["ami"].New, + InstanceType: d.Attributes["instance_type"].New, + } + + log.Printf("Run configuration: %#v", runOpts) + runResp, err := ec2conn.RunInstances(runOpts) + if err != nil { + return nil, fmt.Errorf("Error launching source instance: %s", err) + } + + instance := &runResp.Instances[0] + log.Printf("Instance ID: %s", instance.InstanceId) + + // TODO(mitchellh): wait until running + + rs := s.MergeDiff(d) + rs.ID = instance.InstanceId + rs.Attributes["public_dns"] = instance.DNSName + rs.Attributes["public_ip"] = instance.PublicIpAddress + rs.Attributes["private_dns"] = instance.PrivateDNSName + rs.Attributes["private_ip"] = instance.PrivateIpAddress + + return rs, nil +} + +func resource_aws_instance_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + if s.ID != "" { + panic("OH MY WOW") + } + + return s, nil +} diff --git a/helper/resource/map.go b/helper/resource/map.go new file mode 100644 index 000000000..390070df6 --- /dev/null +++ b/helper/resource/map.go @@ -0,0 +1,68 @@ +package resource + +import ( + "fmt" + + "github.com/hashicorp/terraform/terraform" +) + +// Map is a map of resources that are supported, and provides helpers for +// more easily implementing a ResourceProvider. +type Map struct { + Mapping map[string]Resource +} + +// Apply performs a create or update depending on the diff, and calls +// the proper function on the matching Resource. +func (m *Map) Apply( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + r, ok := m.Mapping[s.Type] + if !ok { + return nil, fmt.Errorf("Unknown resource type: %s", s.Type) + } + + if s.ID == "" { + return r.Create(s, d, meta) + } else { + panic("update no implemented yet") + //return r.Update(s, d, meta) + } +} + +// Refresh performs a Refresh on the proper resource type. +// +// Refresh on the Resource won't be called if the state represents a +// non-created resource (ID is blank). +// +// An error is returned if the resource isn't registered. +func (m *Map) Refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + // If the resource isn't created, don't refresh. + if s.ID == "" { + return s, nil + } + + r, ok := m.Mapping[s.Type] + if !ok { + return nil, fmt.Errorf("Unknown resource type: %s", s.Type) + } + + return r.Refresh(s, meta) +} + +// Resources returns all the resources that are supported by this +// resource map and can be used to satisfy the Resources method of +// a ResourceProvider. +func (m *Map) Resources() []terraform.ResourceType { + rs := make([]terraform.ResourceType, 0, len(m.Mapping)) + for k, _ := range m.Mapping { + rs = append(rs, terraform.ResourceType{ + Name: k, + }) + } + + return rs +} diff --git a/helper/resource/resource.go b/helper/resource/resource.go new file mode 100644 index 000000000..f8620e8c2 --- /dev/null +++ b/helper/resource/resource.go @@ -0,0 +1,30 @@ +package resource + +import ( + "github.com/hashicorp/terraform/terraform" +) + +type Resource struct { + Create CreateFunc + Diff DiffFunc + Refresh RefreshFunc +} + +// CreateFunc is a function that creates a resource that didn't previously +// exist. +type CreateFunc func( + *terraform.ResourceState, + *terraform.ResourceDiff, + interface{}) (*terraform.ResourceState, error) + +// DiffFunc is a function that performs a diff of a resource. +type DiffFunc func( + *terraform.ResourceState, + *terraform.ResourceConfig, + interface{}) (*terraform.ResourceDiff, error) + +// RefreshFunc is a function that performs a refresh of a specific type +// of resource. +type RefreshFunc func( + *terraform.ResourceState, + interface{}) (*terraform.ResourceState, error)