diff --git a/builtin/providers/postgresql/provider.go b/builtin/providers/postgresql/provider.go index 4b73192ad..bec0b46d0 100644 --- a/builtin/providers/postgresql/provider.go +++ b/builtin/providers/postgresql/provider.go @@ -43,8 +43,9 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "postgresql_database": resourcePostgreSQLDatabase(), - "postgresql_role": resourcePostgreSQLRole(), + "postgresql_database": resourcePostgreSQLDatabase(), + "postgresql_role": resourcePostgreSQLRole(), + "postgresql_extension": resourcePostgreSQLExtension(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/postgresql/resource_postgresql_extension.go b/builtin/providers/postgresql/resource_postgresql_extension.go new file mode 100644 index 000000000..d4e990b56 --- /dev/null +++ b/builtin/providers/postgresql/resource_postgresql_extension.go @@ -0,0 +1,92 @@ +package postgresql + +import ( + "database/sql" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" + "github.com/lib/pq" +) + +func resourcePostgreSQLExtension() *schema.Resource { + return &schema.Resource{ + Create: resourcePostgreSQLExtensionCreate, + Read: resourcePostgreSQLExtensionRead, + Delete: resourcePostgreSQLExtensionDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourcePostgreSQLExtensionCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Client) + conn, err := client.Connect() + if err != nil { + return err + } + defer conn.Close() + + extensionName := d.Get("name").(string) + + query := fmt.Sprintf("CREATE EXTENSION %s", pq.QuoteIdentifier(extensionName)) + _, err = conn.Query(query) + if err != nil { + return errwrap.Wrapf("Error creating extension: {{err}}", err) + } + + d.SetId(extensionName) + + return resourcePostgreSQLExtensionRead(d, meta) +} + +func resourcePostgreSQLExtensionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Client) + conn, err := client.Connect() + if err != nil { + return err + } + defer conn.Close() + + extensionName := d.Get("name").(string) + + var hasExtension bool + err = conn.QueryRow("SELECT 1 from pg_extension d WHERE extname=$1", extensionName).Scan(&hasExtension) + switch { + case err == sql.ErrNoRows: + d.SetId("") + return nil + case err != nil: + return errwrap.Wrapf("Error reading extension: {{err}}", err) + default: + d.Set("extension", hasExtension) + return nil + } +} + +func resourcePostgreSQLExtensionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Client) + conn, err := client.Connect() + if err != nil { + return err + } + defer conn.Close() + + extensionName := d.Get("name").(string) + + query := fmt.Sprintf("DROP EXTENSION %s", pq.QuoteIdentifier(extensionName)) + _, err = conn.Query(query) + if err != nil { + return errwrap.Wrapf("Error deleting extension: {{err}}", err) + } + + d.SetId("") + + return nil +} diff --git a/builtin/providers/postgresql/resource_postgresql_extension_test.go b/builtin/providers/postgresql/resource_postgresql_extension_test.go new file mode 100644 index 000000000..78b666e8e --- /dev/null +++ b/builtin/providers/postgresql/resource_postgresql_extension_test.go @@ -0,0 +1,102 @@ +package postgresql + +import ( + "database/sql" + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccPostgresqlExtension_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPostgresqlExtensionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccPostgresqlExtensionConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckPostgresqlExtensionExists("postgresql_extension.myextension"), + resource.TestCheckResourceAttr( + "postgresql_extension.myextension", "name", "pg_trgm"), + ), + }, + }, + }) +} + +func testAccCheckPostgresqlExtensionDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "postgresql_extension" { + continue + } + + exists, err := checkExtensionExists(client, rs.Primary.ID) + + if err != nil { + return fmt.Errorf("Error checking extension %s", err) + } + + if exists { + return fmt.Errorf("Extension still exists after destroy") + } + } + + return nil +} + +func testAccCheckPostgresqlExtensionExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Resource not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + client := testAccProvider.Meta().(*Client) + exists, err := checkExtensionExists(client, rs.Primary.ID) + + if err != nil { + return fmt.Errorf("Error checking extension %s", err) + } + + if !exists { + return fmt.Errorf("Extension not found") + } + + return nil + } +} + +func checkExtensionExists(client *Client, extensionName string) (bool, error) { + conn, err := client.Connect() + if err != nil { + return false, err + } + defer conn.Close() + + var _rez int + err = conn.QueryRow("SELECT 1 from pg_extension d WHERE extname=$1", extensionName).Scan(&_rez) + switch { + case err == sql.ErrNoRows: + return false, nil + case err != nil: + return false, fmt.Errorf("Error reading info about extension: %s", err) + default: + return true, nil + } +} + +var testAccPostgresqlExtensionConfig = ` +resource "postgresql_extension" "myextension" { + name = "pg_trgm" +} +` diff --git a/website/source/docs/providers/postgresql/r/postgresql_extension.html.markdown b/website/source/docs/providers/postgresql/r/postgresql_extension.html.markdown new file mode 100644 index 000000000..ae8a9f26a --- /dev/null +++ b/website/source/docs/providers/postgresql/r/postgresql_extension.html.markdown @@ -0,0 +1,26 @@ +--- +layout: "postgresql" +page_title: "PostgreSQL: postgresql_extension" +sidebar_current: "docs-postgresql-resource-postgresql_extension" +description: |- + Creates and manages an extension on a PostgreSQL server. +--- + +# postgresql\_role + +The ``[pstgresql_extension]`` resource creates and manages an extension on a PostgreSQL +server. + + +## Usage + +``` +resource "postgresql_role" "my_extension" { + name = "pg_trgm" +} + +``` + +## Argument Reference + +* `name` - (Required) The name of the extension. \ No newline at end of file diff --git a/website/source/layouts/postgresql.erb b/website/source/layouts/postgresql.erb index 7375784ce..50aef15a6 100644 --- a/website/source/layouts/postgresql.erb +++ b/website/source/layouts/postgresql.erb @@ -19,6 +19,9 @@