Skip to content

Commit

Permalink
Add security label resource
Browse files Browse the repository at this point in the history
  • Loading branch information
jbunting committed Apr 23, 2024
1 parent 8cf2e13 commit 9f98aa0
Show file tree
Hide file tree
Showing 4 changed files with 397 additions and 0 deletions.
3 changes: 3 additions & 0 deletions postgresql/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
featurePubWithoutTruncate
featureFunction
featureServer
featureSecurityLabel
)

var (
Expand Down Expand Up @@ -112,6 +113,8 @@ var (
featureServer: semver.MustParseRange(">=10.0.0"),

featureDatabaseOwnerRole: semver.MustParseRange(">=15.0.0"),

featureSecurityLabel: semver.MustParseRange(">=11.0.0"),
}
)

Expand Down
1 change: 1 addition & 0 deletions postgresql/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ func Provider() *schema.Provider {
"postgresql_function": resourcePostgreSQLFunction(),
"postgresql_server": resourcePostgreSQLServer(),
"postgresql_user_mapping": resourcePostgreSQLUserMapping(),
"postgresql_security_label": resourcePostgreSQLSecurityLabel(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
182 changes: 182 additions & 0 deletions postgresql/resource_postgresql_security_label.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package postgresql

import (
"bytes"
"database/sql"
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/lib/pq"
)

const (
securityLabelObjectNameAttr = "object_name"
securityLabelObjectTypeAttr = "object_type"
securityLabelProviderAttr = "label_provider"
securityLabelLabelAttr = "label"
)

func resourcePostgreSQLSecurityLabel() *schema.Resource {
return &schema.Resource{
Create: PGResourceFunc(resourcePostgreSQLSecurityLabelCreate),
Read: PGResourceFunc(resourcePostgreSQLSecurityLabelRead),
Update: PGResourceFunc(resourcePostgreSQLSecurityLabelUpdate),
Delete: PGResourceFunc(resourcePostgreSQLSecurityLabelDelete),
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
securityLabelObjectNameAttr: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The name of the existing object to apply the security label to",
},
securityLabelObjectTypeAttr: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The type of the existing object to apply the security label to",
},
securityLabelProviderAttr: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The provider to apply the security label for",
},
securityLabelLabelAttr: {
Type: schema.TypeString,
Required: true,
ForceNew: false,
Description: "The label to be applied",
},
},
}
}

func resourcePostgreSQLSecurityLabelCreate(db *DBConnection, d *schema.ResourceData) error {
if !db.featureSupported(featureSecurityLabel) {
return fmt.Errorf(
"Security Label is not supported for this Postgres version (%s)",
db.version,
)
}
log.Printf("[WARN] PostgreSQL security label Create")
label := d.Get(securityLabelLabelAttr).(string)
if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil {
return err
}

d.SetId(generateSecurityLabelID(d))

return resourcePostgreSQLSecurityLabelReadImpl(db, d)
}

func resourcePostgreSQLSecurityLabelUpdateImpl(db *DBConnection, d *schema.ResourceData, label string) error {
b := bytes.NewBufferString("SECURITY LABEL ")

objectType := d.Get(securityLabelObjectTypeAttr).(string)
objectName := d.Get(securityLabelObjectNameAttr).(string)
provider := d.Get(securityLabelProviderAttr).(string)
fmt.Fprint(b, " FOR ", pq.QuoteIdentifier(provider))
fmt.Fprint(b, " ON ", objectType, pq.QuoteIdentifier(objectName))
fmt.Fprint(b, " IS ", label)

if _, err := db.Exec(b.String()); err != nil {
log.Printf("[WARN] PostgreSQL security label Create failed %s", err)
return err
}
return nil
}

func resourcePostgreSQLSecurityLabelRead(db *DBConnection, d *schema.ResourceData) error {
if !db.featureSupported(featureSecurityLabel) {
return fmt.Errorf(
"Security Label is not supported for this Postgres version (%s)",
db.version,
)
}
log.Printf("[WARN] PostgreSQL security label Read")

return resourcePostgreSQLSecurityLabelReadImpl(db, d)
}

func resourcePostgreSQLSecurityLabelReadImpl(db *DBConnection, d *schema.ResourceData) error {
objectType := d.Get(securityLabelObjectTypeAttr).(string)
objectName := d.Get(securityLabelObjectNameAttr).(string)
provider := d.Get(securityLabelProviderAttr).(string)

txn, err := startTransaction(db.client, "")
if err != nil {
return err
}
defer deferredRollback(txn)

query := "SELECT objtype, objname, provider, label FROM pg_seclabels WHERE objtype = $1 and objname = $2 and provider = $3"
row := db.QueryRow(query, objectType, objectName, provider)

var label string
err = row.Scan(&objectType, &objectName, &provider, &label)
switch {
case err == sql.ErrNoRows:
log.Printf("[WARN] PostgreSQL security label for (%s '%s') with provider %s not found", objectType, objectName, provider)
d.SetId("")
return nil
case err != nil:
return fmt.Errorf("Error reading security label: %w", err)
}

d.Set(securityLabelObjectTypeAttr, objectType)
d.Set(securityLabelObjectNameAttr, objectName)
d.Set(securityLabelProviderAttr, provider)
d.Set(securityLabelLabelAttr, label)
d.SetId(generateSecurityLabelID(d))

return nil
}

func resourcePostgreSQLSecurityLabelDelete(db *DBConnection, d *schema.ResourceData) error {
if !db.featureSupported(featureSecurityLabel) {
return fmt.Errorf(
"Security Label is not supported for this Postgres version (%s)",
db.version,
)
}
log.Printf("[WARN] PostgreSQL security label Delete")

if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, "NULL"); err != nil {
return err
}

d.SetId("")

return nil
}

func resourcePostgreSQLSecurityLabelUpdate(db *DBConnection, d *schema.ResourceData) error {
if !db.featureSupported(featureServer) {
return fmt.Errorf(
"Security Label is not supported for this Postgres version (%s)",
db.version,
)
}
log.Printf("[WARN] PostgreSQL security label Update")

label := d.Get(securityLabelLabelAttr).(string)
if err := resourcePostgreSQLSecurityLabelUpdateImpl(db, d, pq.QuoteLiteral(label)); err != nil {
return err
}

return resourcePostgreSQLSecurityLabelReadImpl(db, d)
}

func generateSecurityLabelID(d *schema.ResourceData) string {
return strings.Join([]string{
d.Get(securityLabelProviderAttr).(string),
d.Get(securityLabelObjectTypeAttr).(string),
d.Get(securityLabelObjectNameAttr).(string),
}, ".")
}
Loading

0 comments on commit 9f98aa0

Please sign in to comment.