github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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 }