From 7632458ad3beef3ef2b15522e66a54b19ba1bdd8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 11 Mar 2015 18:17:47 -0500 Subject: [PATCH 1/2] providers/terraform: remote state resource --- builtin/bins/provider-terraform/main.go | 12 ++++ builtin/bins/provider-terraform/main_test.go | 1 + builtin/providers/terraform/provider.go | 15 ++++ builtin/providers/terraform/provider_test.go | 31 ++++++++ builtin/providers/terraform/resource_state.go | 71 +++++++++++++++++++ .../terraform/resource_state_test.go | 54 ++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 builtin/bins/provider-terraform/main.go create mode 100644 builtin/bins/provider-terraform/main_test.go create mode 100644 builtin/providers/terraform/provider.go create mode 100644 builtin/providers/terraform/provider_test.go create mode 100644 builtin/providers/terraform/resource_state.go create mode 100644 builtin/providers/terraform/resource_state_test.go diff --git a/builtin/bins/provider-terraform/main.go b/builtin/bins/provider-terraform/main.go new file mode 100644 index 000000000..21f4da5d2 --- /dev/null +++ b/builtin/bins/provider-terraform/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/hashicorp/terraform/builtin/providers/terraform" + "github.com/hashicorp/terraform/plugin" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + ProviderFunc: terraform.Provider, + }) +} diff --git a/builtin/bins/provider-terraform/main_test.go b/builtin/bins/provider-terraform/main_test.go new file mode 100644 index 000000000..06ab7d0f9 --- /dev/null +++ b/builtin/bins/provider-terraform/main_test.go @@ -0,0 +1 @@ +package main diff --git a/builtin/providers/terraform/provider.go b/builtin/providers/terraform/provider.go new file mode 100644 index 000000000..0330ce775 --- /dev/null +++ b/builtin/providers/terraform/provider.go @@ -0,0 +1,15 @@ +package terraform + +import ( + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +// Provider returns a terraform.ResourceProvider. +func Provider() terraform.ResourceProvider { + return &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "terraform_state": resourceState(), + }, + } +} diff --git a/builtin/providers/terraform/provider_test.go b/builtin/providers/terraform/provider_test.go new file mode 100644 index 000000000..65f3ce4ad --- /dev/null +++ b/builtin/providers/terraform/provider_test.go @@ -0,0 +1,31 @@ +package terraform + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +var testAccProviders map[string]terraform.ResourceProvider +var testAccProvider *schema.Provider + +func init() { + testAccProvider = Provider().(*schema.Provider) + testAccProviders = map[string]terraform.ResourceProvider{ + "terraform": testAccProvider, + } +} + +func TestProvider(t *testing.T) { + if err := Provider().(*schema.Provider).InternalValidate(); err != nil { + t.Fatalf("err: %s", err) + } +} + +func TestProvider_impl(t *testing.T) { + var _ terraform.ResourceProvider = Provider() +} + +func testAccPreCheck(t *testing.T) { +} diff --git a/builtin/providers/terraform/resource_state.go b/builtin/providers/terraform/resource_state.go new file mode 100644 index 000000000..85de3990d --- /dev/null +++ b/builtin/providers/terraform/resource_state.go @@ -0,0 +1,71 @@ +package terraform + +import ( + "log" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/state/remote" +) + +func resourceState() *schema.Resource { + return &schema.Resource{ + Create: resourceStateCreate, + Read: resourceStateRead, + Delete: resourceStateDelete, + + Schema: map[string]*schema.Schema{ + "backend": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "config": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + + "output": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + }, + } +} + +func resourceStateCreate(d *schema.ResourceData, meta interface{}) error { + return resourceStateRead(d, meta) +} + +func resourceStateRead(d *schema.ResourceData, meta interface{}) error { + backend := d.Get("backend").(string) + config := make(map[string]string) + for k, v := range d.Get("config").(map[string]interface{}) { + config[k] = v.(string) + } + + // Create the client to access our remote state + log.Printf("[DEBUG] Initializing remote state client: %s", backend) + client, err := remote.NewClient(backend, config) + if err != nil { + return err + } + + // Create the remote state itself and refresh it in order to load the state + log.Printf("[DEBUG] Loading remote state...") + state := &remote.State{Client: client} + if err := state.RefreshState(); err != nil { + return err + } + + d.SetId(time.Now().UTC().String()) + d.Set("output", state.State().RootModule().Outputs) + return nil +} + +func resourceStateDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} diff --git a/builtin/providers/terraform/resource_state_test.go b/builtin/providers/terraform/resource_state_test.go new file mode 100644 index 000000000..6db173503 --- /dev/null +++ b/builtin/providers/terraform/resource_state_test.go @@ -0,0 +1,54 @@ +package terraform + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccState_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccState_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckStateValue( + "terraform_state.foo", "foo", "bar"), + ), + }, + }, + }) +} + +func testAccCheckStateValue(id, name, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[id] + if !ok { + return fmt.Errorf("Not found: %s", id) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + v := rs.Primary.Attributes["output."+name] + if v != value { + return fmt.Errorf( + "Value for %s is %s, not %s", name, v, value) + } + + return nil + } +} + +const testAccState_basic = ` +resource "terraform_state" "foo" { + backend = "_local" + + config { + path = "./test-fixtures/basic.tfstate" + } +}` From 478379b3b32414737a5bc8cca34f433d9b451a61 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 1 Apr 2015 22:49:05 -0700 Subject: [PATCH 2/2] providers/terraform: name it terraform_remote_state --- builtin/providers/terraform/provider.go | 2 +- builtin/providers/terraform/resource_state.go | 23 +++++++++++-------- .../terraform/resource_state_test.go | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/builtin/providers/terraform/provider.go b/builtin/providers/terraform/provider.go index 0330ce775..e71d5f40a 100644 --- a/builtin/providers/terraform/provider.go +++ b/builtin/providers/terraform/provider.go @@ -9,7 +9,7 @@ import ( func Provider() terraform.ResourceProvider { return &schema.Provider{ ResourcesMap: map[string]*schema.Resource{ - "terraform_state": resourceState(), + "terraform_remote_state": resourceRemoteState(), }, } } diff --git a/builtin/providers/terraform/resource_state.go b/builtin/providers/terraform/resource_state.go index 85de3990d..fb0e85ee2 100644 --- a/builtin/providers/terraform/resource_state.go +++ b/builtin/providers/terraform/resource_state.go @@ -8,11 +8,11 @@ import ( "github.com/hashicorp/terraform/state/remote" ) -func resourceState() *schema.Resource { +func resourceRemoteState() *schema.Resource { return &schema.Resource{ - Create: resourceStateCreate, - Read: resourceStateRead, - Delete: resourceStateDelete, + Create: resourceRemoteStateCreate, + Read: resourceRemoteStateRead, + Delete: resourceRemoteStateDelete, Schema: map[string]*schema.Schema{ "backend": &schema.Schema{ @@ -35,11 +35,11 @@ func resourceState() *schema.Resource { } } -func resourceStateCreate(d *schema.ResourceData, meta interface{}) error { - return resourceStateRead(d, meta) +func resourceRemoteStateCreate(d *schema.ResourceData, meta interface{}) error { + return resourceRemoteStateRead(d, meta) } -func resourceStateRead(d *schema.ResourceData, meta interface{}) error { +func resourceRemoteStateRead(d *schema.ResourceData, meta interface{}) error { backend := d.Get("backend").(string) config := make(map[string]string) for k, v := range d.Get("config").(map[string]interface{}) { @@ -60,12 +60,17 @@ func resourceStateRead(d *schema.ResourceData, meta interface{}) error { return err } + var outputs map[string]string + if !state.State().Empty() { + outputs = state.State().RootModule().Outputs + } + d.SetId(time.Now().UTC().String()) - d.Set("output", state.State().RootModule().Outputs) + d.Set("output", outputs) return nil } -func resourceStateDelete(d *schema.ResourceData, meta interface{}) error { +func resourceRemoteStateDelete(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } diff --git a/builtin/providers/terraform/resource_state_test.go b/builtin/providers/terraform/resource_state_test.go index 6db173503..42ad55ada 100644 --- a/builtin/providers/terraform/resource_state_test.go +++ b/builtin/providers/terraform/resource_state_test.go @@ -17,7 +17,7 @@ func TestAccState_basic(t *testing.T) { Config: testAccState_basic, Check: resource.ComposeTestCheckFunc( testAccCheckStateValue( - "terraform_state.foo", "foo", "bar"), + "terraform_remote_state.foo", "foo", "bar"), ), }, }, @@ -45,7 +45,7 @@ func testAccCheckStateValue(id, name, value string) resource.TestCheckFunc { } const testAccState_basic = ` -resource "terraform_state" "foo" { +resource "terraform_remote_state" "foo" { backend = "_local" config {