Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add security label resource #365

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not well versed in writing Terraform providers but does this mean the resource supports importing? I personally feel importing is quite important to help with adoption and so it this is the case I think it makes sense to add an import example similar to a lot of the other resources?

image

Or even simpler:
image

},

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 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few lines contain quoteliteral(label), what might cause the issue with quotes in the label Objname reported before. Could you please try to make it work - to create objname/label without quotes in postgresql?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query := "SELECT objtype, objname, provider, label FROM pg_seclabels WHERE objtype = $1 and objname = quote_literal($2) and provider = $3"

I'm no go language developer to test it, but based on the chatgpt this should fix the issue

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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned by other numbers, you need quote_ident on objname.

SELECT objtype, objname, provider, label FROM pg_seclabels WHERE objtype = $1 and objname = quote_ident($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