diff --git a/postgresql/resource_postgresql_grant.go b/postgresql/resource_postgresql_grant.go index 747383b1..b6e1de71 100644 --- a/postgresql/resource_postgresql_grant.go +++ b/postgresql/resource_postgresql_grant.go @@ -1,9 +1,11 @@ package postgresql import ( + "context" "database/sql" "fmt" "log" + "strconv" "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -43,6 +45,9 @@ func resourcePostgreSQLGrant() *schema.Resource { Update: PGResourceFunc(resourcePostgreSQLGrantUpdate), Read: PGResourceFunc(resourcePostgreSQLGrantRead), Delete: PGResourceFunc(resourcePostgreSQLGrantDelete), + Importer: &schema.ResourceImporter{ + StateContext: resourcePostgreSQLGrantImport, + }, Schema: map[string]*schema.Schema{ "role": { @@ -104,6 +109,68 @@ func resourcePostgreSQLGrant() *schema.Resource { } } +func resourcePostgreSQLGrantImport(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + importId := d.Id() + parts := strings.Split(importId, "@") + + if len(parts) != 7 { + return nil, fmt.Errorf("invalid import id. Expected format: @@@[]@[]@[]@. Got %s", importId) + } + + role := parts[0] + d.Set("role", role) + database := parts[1] + d.Set("database", database) + objectType := parts[2] + d.Set("object_type", objectType) + schema_ := parts[3] + if objectType != "database" { + d.Set("schema", schema_) + } + objects := strings.Split(parts[4], ",") + if objectType == "database" || objectType == "schema" { + if parts[4] != "" { + return nil, fmt.Errorf("objects not expected for object type %s. Got: %s", objectType, parts[4]) + } + } else { + if objectType == "column" { + if len(objects) != 1 { + return nil, fmt.Errorf("only one object is expected for object type %s. Got: %s", objectType, parts[4]) + } + } + objectSet := schema.NewSet(schema.HashString, []any{}) + for _, object := range objects { + objectSet.Add(object) + } + d.Set("objects", objectSet) + } + + columns := strings.Split(parts[5], ",") + if objectType == "column" { + if len(columns) == 0 { + return nil, fmt.Errorf("expected at least one column for object type %s. Got: %s", objectType, parts[5]) + } + columnSet := schema.NewSet(schema.HashString, []any{}) + for _, column := range columns { + columnSet.Add(column) + } + d.Set("columns", columnSet) + } else { + if parts[5] != "" { + return nil, fmt.Errorf("columns not expected for object type %s. Got: %s", objectType, parts[5]) + } + } + + withGrantOption, err := strconv.ParseBool(parts[6]) + if err != nil { + return nil, fmt.Errorf("error parsing with_grant_option: %w. Got: %s", err, parts[6]) + } + d.Set("with_grant_option", withGrantOption) + + d.SetId(generateGrantID(d)) // Import ID is the same as the generated ID for backwards compatibility + return []*schema.ResourceData{d}, nil +} + func resourcePostgreSQLGrantRead(db *DBConnection, d *schema.ResourceData) error { if err := validateFeatureSupport(db, d); err != nil { return fmt.Errorf("feature is not supported: %v", err) diff --git a/website/docs/r/postgresql_grant.html.markdown b/website/docs/r/postgresql_grant.html.markdown index a31252af..25a9be4c 100644 --- a/website/docs/r/postgresql_grant.html.markdown +++ b/website/docs/r/postgresql_grant.html.markdown @@ -65,3 +65,30 @@ resource "postgresql_grant" "revoke_public" { privileges = [] } ``` + +## Import + +`postgresql_grant` supports importing resources following the format: + +``` +@@@[]@[]@[]@ +``` + +Field positions have to be maintained. If the resource you are importing doesn't have a value +for a field (`schema`, `objects` or `columns`), you should use an empty string for that field. + +For example: + +```tf +resource "postgresql_grant" "demo" { + database = "test_db" + role = "demo" + schema = "public" + object_type = "schema" + privileges = ["USAGE", "CREATE"] +} +``` + +```bash +terraform import postgresql_grant.demo demo@test_db@schema@public@@@false +```