From c556e2ad48a3d87a72b62ad469c0d243c01bf7d8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 23 Jun 2014 19:01:57 -0700 Subject: [PATCH] providers/aws: start filling out --- builtin/providers/aws/config.go | 46 +++++++++++++++ builtin/providers/aws/diff.go | 1 - builtin/providers/aws/refresh.go | 31 ++++++++++ builtin/providers/aws/resource_provider.go | 56 ++++++++++++++++--- .../providers/aws/resource_provider_test.go | 32 +++++++++++ helper/config/decode.go | 28 ++++++++++ terraform/terraform.go | 5 +- 7 files changed, 186 insertions(+), 13 deletions(-) create mode 100644 builtin/providers/aws/config.go create mode 100644 builtin/providers/aws/refresh.go create mode 100644 helper/config/decode.go diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go new file mode 100644 index 000000000000..6fae6ac105aa --- /dev/null +++ b/builtin/providers/aws/config.go @@ -0,0 +1,46 @@ +package aws + +import ( + "strings" + "unicode" + + "github.com/mitchellh/goamz/aws" +) + +type Config struct { + AccessKey string `mapstructure:"access_key"` + SecretKey string `mapstructure:"secret_key"` + Region string `mapstructure:"region"` +} + +// AWSAuth returns a valid aws.Auth object for access to AWS services, or +// an error if the authentication couldn't be resolved. +// +// TODO(mitchellh): Test in some way. +func (c *Config) AWSAuth() (aws.Auth, error) { + auth, err := aws.GetAuth(c.AccessKey, c.SecretKey) + if err == nil { + // Store the accesskey and secret that we got... + c.AccessKey = auth.AccessKey + c.SecretKey = auth.SecretKey + } + + return auth, err +} + +// AWSRegion returns the configured region. +// +// TODO(mitchellh): Test in some way. +func (c *Config) AWSRegion() (aws.Region, error) { + if c.Region != "" { + return aws.Regions[c.Region], nil + } + + md, err := aws.GetMetaData("placement/availability-zone") + if err != nil { + return aws.Region{}, err + } + + region := strings.TrimRightFunc(string(md), unicode.IsLetter) + return aws.Regions[region], nil +} diff --git a/builtin/providers/aws/diff.go b/builtin/providers/aws/diff.go index 8c5e79ba87f4..68c930a63820 100644 --- a/builtin/providers/aws/diff.go +++ b/builtin/providers/aws/diff.go @@ -27,7 +27,6 @@ func diffBuilder_aws_instance() *diff.ResourceBuilder { "ami", "availability_zone", "instance_type", - "region", }, } } diff --git a/builtin/providers/aws/refresh.go b/builtin/providers/aws/refresh.go new file mode 100644 index 000000000000..16d23bdbeed2 --- /dev/null +++ b/builtin/providers/aws/refresh.go @@ -0,0 +1,31 @@ +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 fb2930a12b76..7b11f13123ac 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -2,23 +2,52 @@ package aws import ( "fmt" + "log" + "github.com/hashicorp/terraform/helper/config" "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/ec2" ) type ResourceProvider struct { + Config Config + + ec2conn *ec2.EC2 } func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) { - errs := c.CheckSet([]string{ - "access_key", - "secret_key", - }) - - return nil, errs + return nil, nil } -func (p *ResourceProvider) Configure(*terraform.ResourceConfig) error { +func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { + if _, err := config.Decode(&p.Config, c.Config); err != nil { + return err + } + + // Get the auth and region. This can fail if keys/regions were not + // specified and we're attempting to use the environment. + var errs []error + log.Println("Building AWS auth structure") + auth, err := p.Config.AWSAuth() + if err != nil { + errs = append(errs, err) + } + + log.Println("Building AWS region structure") + region, err := p.Config.AWSRegion() + if err != nil { + errs = append(errs, err) + } + + if len(errs) == 0 { + log.Println("Initializing EC2 connection") + p.ec2conn = ec2.New(auth, region) + } + + if len(errs) > 0 { + return &terraform.MultiError{Errors: errs} + } + return nil } @@ -50,7 +79,18 @@ func (p *ResourceProvider) Diff( func (p *ResourceProvider) Refresh( s *terraform.ResourceState) (*terraform.ResourceState, error) { - return s, nil + // 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) } func (p *ResourceProvider) Resources() []terraform.ResourceType { diff --git a/builtin/providers/aws/resource_provider_test.go b/builtin/providers/aws/resource_provider_test.go index 3e6b7a12c3a9..433e94b2eb75 100644 --- a/builtin/providers/aws/resource_provider_test.go +++ b/builtin/providers/aws/resource_provider_test.go @@ -1,11 +1,43 @@ package aws import ( + "reflect" "testing" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/terraform" ) func TestResourceProvider_impl(t *testing.T) { var _ terraform.ResourceProvider = new(ResourceProvider) } + +func TestResourceProvider_Configure(t *testing.T) { + rp := new(ResourceProvider) + + raw := map[string]interface{}{ + "access_key": "foo", + "secret_key": "bar", + "region": "us-east", + } + + rawConfig, err := config.NewRawConfig(raw) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = rp.Configure(terraform.NewResourceConfig(rawConfig)) + if err != nil { + t.Fatalf("err: %s", err) + } + + expected := Config{ + AccessKey: "foo", + SecretKey: "bar", + Region: "us-east", + } + + if !reflect.DeepEqual(rp.Config, expected) { + t.Fatalf("bad: %#v", rp.Config) + } +} diff --git a/helper/config/decode.go b/helper/config/decode.go new file mode 100644 index 000000000000..f470c9b4beeb --- /dev/null +++ b/helper/config/decode.go @@ -0,0 +1,28 @@ +package config + +import ( + "github.com/mitchellh/mapstructure" +) + +func Decode(target interface{}, raws ...interface{}) (*mapstructure.Metadata, error) { + var md mapstructure.Metadata + decoderConfig := &mapstructure.DecoderConfig{ + Metadata: &md, + Result: target, + WeaklyTypedInput: true, + } + + decoder, err := mapstructure.NewDecoder(decoderConfig) + if err != nil { + return nil, err + } + + for _, raw := range raws { + err := decoder.Decode(raw) + if err != nil { + return nil, err + } + } + + return &md, nil +} diff --git a/terraform/terraform.go b/terraform/terraform.go index 55085ca81588..0168406591aa 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -340,10 +340,7 @@ func (t *terraformProvider) init(vars map[string]string) (err error) { panic(err) } - rc = &ResourceConfig{ - ComputedKeys: t.Config.RawConfig.UnknownKeys(), - Raw: t.Config.RawConfig.Config(), - } + rc = NewResourceConfig(t.Config.RawConfig) } err = t.Provider.Configure(rc)