github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/postgresql/resource_postgresql_extension.go (about)

     1  package postgresql
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"errors"
     7  	"fmt"
     8  	"log"
     9  
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"github.com/lib/pq"
    13  )
    14  
    15  const (
    16  	extNameAttr    = "name"
    17  	extSchemaAttr  = "schema"
    18  	extVersionAttr = "version"
    19  )
    20  
    21  func resourcePostgreSQLExtension() *schema.Resource {
    22  	return &schema.Resource{
    23  		Create: resourcePostgreSQLExtensionCreate,
    24  		Read:   resourcePostgreSQLExtensionRead,
    25  		Update: resourcePostgreSQLExtensionUpdate,
    26  		Delete: resourcePostgreSQLExtensionDelete,
    27  		Exists: resourcePostgreSQLExtensionExists,
    28  		Importer: &schema.ResourceImporter{
    29  			State: schema.ImportStatePassthrough,
    30  		},
    31  
    32  		Schema: map[string]*schema.Schema{
    33  			extNameAttr: {
    34  				Type:     schema.TypeString,
    35  				Required: true,
    36  				ForceNew: true,
    37  			},
    38  			extSchemaAttr: {
    39  				Type:        schema.TypeString,
    40  				Optional:    true,
    41  				Computed:    true,
    42  				Description: "Sets the schema of an extension",
    43  			},
    44  			extVersionAttr: {
    45  				Type:        schema.TypeString,
    46  				Optional:    true,
    47  				Computed:    true,
    48  				Description: "Sets the version number of the extension",
    49  			},
    50  		},
    51  	}
    52  }
    53  
    54  func resourcePostgreSQLExtensionCreate(d *schema.ResourceData, meta interface{}) error {
    55  	c := meta.(*Client)
    56  	c.catalogLock.Lock()
    57  	defer c.catalogLock.Unlock()
    58  
    59  	conn, err := c.Connect()
    60  	if err != nil {
    61  		return err
    62  	}
    63  	defer conn.Close()
    64  
    65  	extName := d.Get(extNameAttr).(string)
    66  
    67  	b := bytes.NewBufferString("CREATE EXTENSION ")
    68  	fmt.Fprint(b, pq.QuoteIdentifier(extName))
    69  
    70  	if v, ok := d.GetOk(extSchemaAttr); ok {
    71  		fmt.Fprint(b, " SCHEMA ", pq.QuoteIdentifier(v.(string)))
    72  	}
    73  
    74  	if v, ok := d.GetOk(extVersionAttr); ok {
    75  		fmt.Fprint(b, " VERSION ", pq.QuoteIdentifier(v.(string)))
    76  	}
    77  
    78  	query := b.String()
    79  	_, err = conn.Query(query)
    80  	if err != nil {
    81  		return errwrap.Wrapf("Error creating extension: {{err}}", err)
    82  	}
    83  
    84  	d.SetId(extName)
    85  
    86  	return resourcePostgreSQLExtensionReadImpl(d, meta)
    87  }
    88  
    89  func resourcePostgreSQLExtensionExists(d *schema.ResourceData, meta interface{}) (bool, error) {
    90  	c := meta.(*Client)
    91  	c.catalogLock.Lock()
    92  	defer c.catalogLock.Unlock()
    93  
    94  	conn, err := c.Connect()
    95  	if err != nil {
    96  		return false, err
    97  	}
    98  	defer conn.Close()
    99  
   100  	var extName string
   101  	err = conn.QueryRow("SELECT extname FROM pg_catalog.pg_extension WHERE extname = $1", d.Id()).Scan(&extName)
   102  	switch {
   103  	case err == sql.ErrNoRows:
   104  		return false, nil
   105  	case err != nil:
   106  		return false, err
   107  	}
   108  
   109  	return true, nil
   110  }
   111  
   112  func resourcePostgreSQLExtensionRead(d *schema.ResourceData, meta interface{}) error {
   113  	c := meta.(*Client)
   114  	c.catalogLock.RLock()
   115  	defer c.catalogLock.RUnlock()
   116  
   117  	return resourcePostgreSQLExtensionReadImpl(d, meta)
   118  }
   119  
   120  func resourcePostgreSQLExtensionReadImpl(d *schema.ResourceData, meta interface{}) error {
   121  	c := meta.(*Client)
   122  
   123  	conn, err := c.Connect()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	defer conn.Close()
   128  
   129  	extID := d.Id()
   130  	var extName, extSchema, extVersion string
   131  	err = conn.QueryRow("SELECT e.extname, n.nspname, e.extversion FROM pg_catalog.pg_extension e, pg_catalog.pg_namespace n WHERE n.oid = e.extnamespace AND e.extname = $1", extID).Scan(&extName, &extSchema, &extVersion)
   132  	switch {
   133  	case err == sql.ErrNoRows:
   134  		log.Printf("[WARN] PostgreSQL extension (%s) not found", d.Id())
   135  		d.SetId("")
   136  		return nil
   137  	case err != nil:
   138  		return errwrap.Wrapf("Error reading extension: {{err}}", err)
   139  	default:
   140  		d.Set(extNameAttr, extName)
   141  		d.Set(extSchemaAttr, extSchema)
   142  		d.Set(extVersionAttr, extVersion)
   143  		d.SetId(extName)
   144  		return nil
   145  	}
   146  }
   147  
   148  func resourcePostgreSQLExtensionDelete(d *schema.ResourceData, meta interface{}) error {
   149  	c := meta.(*Client)
   150  	c.catalogLock.Lock()
   151  	defer c.catalogLock.Unlock()
   152  
   153  	conn, err := c.Connect()
   154  	if err != nil {
   155  		return err
   156  	}
   157  	defer conn.Close()
   158  
   159  	extID := d.Id()
   160  
   161  	query := fmt.Sprintf("DROP EXTENSION %s", pq.QuoteIdentifier(extID))
   162  	_, err = conn.Query(query)
   163  	if err != nil {
   164  		return errwrap.Wrapf("Error deleting extension: {{err}}", err)
   165  	}
   166  
   167  	d.SetId("")
   168  
   169  	return nil
   170  }
   171  
   172  func resourcePostgreSQLExtensionUpdate(d *schema.ResourceData, meta interface{}) error {
   173  	c := meta.(*Client)
   174  	c.catalogLock.Lock()
   175  	defer c.catalogLock.Unlock()
   176  
   177  	conn, err := c.Connect()
   178  	if err != nil {
   179  		return err
   180  	}
   181  	defer conn.Close()
   182  
   183  	// Can't rename a schema
   184  
   185  	if err := setExtSchema(conn, d); err != nil {
   186  		return err
   187  	}
   188  
   189  	if err := setExtVersion(conn, d); err != nil {
   190  		return err
   191  	}
   192  
   193  	return resourcePostgreSQLExtensionReadImpl(d, meta)
   194  }
   195  
   196  func setExtSchema(conn *sql.DB, d *schema.ResourceData) error {
   197  	if !d.HasChange(extSchemaAttr) {
   198  		return nil
   199  	}
   200  
   201  	extID := d.Id()
   202  	_, nraw := d.GetChange(extSchemaAttr)
   203  	n := nraw.(string)
   204  	if n == "" {
   205  		return errors.New("Error setting extension name to an empty string")
   206  	}
   207  
   208  	query := fmt.Sprintf("ALTER EXTENSION %s SET SCHEMA %s", pq.QuoteIdentifier(extID), pq.QuoteIdentifier(n))
   209  	if _, err := conn.Query(query); err != nil {
   210  		return errwrap.Wrapf("Error updating extension SCHEMA: {{err}}", err)
   211  	}
   212  
   213  	return nil
   214  }
   215  
   216  func setExtVersion(conn *sql.DB, d *schema.ResourceData) error {
   217  	if !d.HasChange(extVersionAttr) {
   218  		return nil
   219  	}
   220  
   221  	extID := d.Id()
   222  
   223  	b := bytes.NewBufferString("ALTER EXTENSION ")
   224  	fmt.Fprintf(b, "%s UPDATE", pq.QuoteIdentifier(extID))
   225  
   226  	_, nraw := d.GetChange(extVersionAttr)
   227  	n := nraw.(string)
   228  	if n != "" {
   229  		fmt.Fprintf(b, " TO %s", pq.QuoteIdentifier(n))
   230  	}
   231  
   232  	query := b.String()
   233  	if _, err := conn.Query(query); err != nil {
   234  		return errwrap.Wrapf("Error updating extension version: {{err}}", err)
   235  	}
   236  
   237  	return nil
   238  }