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..e71d5f40a --- /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_remote_state": resourceRemoteState(), + }, + } +} 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..fb0e85ee2 --- /dev/null +++ b/builtin/providers/terraform/resource_state.go @@ -0,0 +1,76 @@ +package terraform + +import ( + "log" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/state/remote" +) + +func resourceRemoteState() *schema.Resource { + return &schema.Resource{ + Create: resourceRemoteStateCreate, + Read: resourceRemoteStateRead, + Delete: resourceRemoteStateDelete, + + 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 resourceRemoteStateCreate(d *schema.ResourceData, meta interface{}) error { + return resourceRemoteStateRead(d, meta) +} + +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{}) { + 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 + } + + var outputs map[string]string + if !state.State().Empty() { + outputs = state.State().RootModule().Outputs + } + + d.SetId(time.Now().UTC().String()) + d.Set("output", outputs) + return nil +} + +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 new file mode 100644 index 000000000..42ad55ada --- /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_remote_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_remote_state" "foo" { + backend = "_local" + + config { + path = "./test-fixtures/basic.tfstate" + } +}`