Skip to content

Commit

Permalink
fix(postgresql_role): Postgresql 16 compatibility (with new roles man…
Browse files Browse the repository at this point in the history
…agement) (#407)
  • Loading branch information
librucha committed Oct 15, 2024
1 parent dea1401 commit 6472ad1
Show file tree
Hide file tree
Showing 20 changed files with 677 additions and 64 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.20.x
go-version: 1.23.x

- run: go mod vendor

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.53
version: v1.61
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: '1.23'
-
name: Import GPG key
id: import_gpg
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
pgversion: [15, 14, 13, 12, 11]
pgversion: [16, 15, 14, 13, 12, 11]

env:
PGVERSION: ${{ matrix.pgversion }}
Expand All @@ -24,7 +24,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.23'

- name: test
run: make test
Expand Down
154 changes: 148 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,149 @@
./*.tfstate
.terraform/
.terraform.lock.hcl*
*.log
.*.swp
tests/docker-compose.*.yml
terraform-provider-postgresql

### JetBrains+all template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser


### Linux template
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*

### Go template
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work

### Windows template
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

.terraform
.terraform.lock.hcl
terraform.tfstate*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Requirements
------------

- [Terraform](https://www.terraform.io/downloads.html) 0.12.x
- [Go](https://golang.org/doc/install) 1.16 (to build the provider plugin)
- [Go](https://golang.org/doc/install) 1.21 (to build the provider plugin)

Building The Provider
---------------------
Expand Down
13 changes: 13 additions & 0 deletions examples/issues/407/dev.tfrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# See https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers
# Use `go build -o ./examples/issues/407/postgresql/terraform-provider-postgresql` in the project root to build the provider.
# Then run terraform in this example directory.

# terraform init
# TF_CLI_CONFIG_FILE=dev.tfrc terraform apply

provider_installation {
dev_overrides {
"cyrilgdn/postgresql" = "./postgresql"
}
direct {}
}
25 changes: 25 additions & 0 deletions examples/issues/407/test.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
terraform {
required_version = ">= 1.0"

required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
version = "~>1"
}
}
}

provider "postgresql" {
superuser = false
port = 25432
username = "rds"
password = "rds"
sslmode = "disable"
}

resource "postgresql_role" "test_role_with_createrole_self_grant" {
name = "test_role_with_createrole_self_grant"
parameters {
createrole_self_grant = "set,inherit"
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/terraform-providers/terraform-provider-postgresql

go 1.20
go 1.23

require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
Expand Down
5 changes: 5 additions & 0 deletions postgresql/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const (
featurePubWithoutTruncate
featureFunction
featureServer
featureCreateRoleSelfGrant
)

var (
Expand Down Expand Up @@ -115,6 +116,10 @@ var (
featureServer: semver.MustParseRange(">=10.0.0"),

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

// New privileges rules in version 16
// https://www.postgresql.org/docs/16/release-16.html#RELEASE-16-PRIVILEGES
featureCreateRoleSelfGrant: semver.MustParseRange(">=16.0.0"),
}
)

Expand Down
37 changes: 36 additions & 1 deletion postgresql/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package postgresql

import (
"context"
"database/sql"
"fmt"
"github.com/hashicorp/terraform-plugin-log/tflog"
"os"
"regexp"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"

"github.com/blang/semver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand Down Expand Up @@ -363,6 +365,39 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
}
}

err := checkCreateRoleSelfGrant(config)
if err != nil {
return nil, err
}

client := config.NewClient(d.Get("database").(string))
return client, nil
}

func checkCreateRoleSelfGrant(config Config) error {
client := config.NewClient("postgres")
connect, err := client.Connect()
if err != nil {
return err
}

username := config.Username

if connect.featureSupported(featureCreateRoleSelfGrant) && !config.Superuser {
var paramValue string
query := `SELECT coalesce(replace(jsonb_path_query_first(to_jsonb(rolconfig),'$[*] ? (@ like_regex "^createrole_self_grant=")')::TEXT,'%[1]s=',''), '') FROM pg_catalog.pg_roles WHERE rolname = $1`
err := connect.QueryRow(query, username).Scan(&paramValue)
switch {
case err == sql.ErrNoRows:
// They don't have a parameter, just skip
break
case err != nil:
tflog.Debug(context.Background(), fmt.Sprintf("User %s parameters cannot be checked: %v", username, err))
}
if !regexp.MustCompile(`^set\s*,\s*inherit$|^inherit\s*,\s*set$`).MatchString(paramValue) {
msg := fmt.Sprintf("Provider user %[1]s has not configured property 'createrole_self_grant' properly. Creating new roles will not create non admin grants by default. You can set it by \"ALTER ROLE '%[1]s' SET createrole_self_grant 'set, inherit';\"", username)
tflog.Warn(context.Background(), msg)
}
}
return nil
}
31 changes: 31 additions & 0 deletions postgresql/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,37 @@ func TestProvider_impl(t *testing.T) {
var _ *schema.Provider = Provider()
}

func TestAccProviderSetCreateRoleSelfGrant(t *testing.T) {
skipIfNotAcc(t)

config := getTestConfig(t)
client := config.NewClient("postgres")
db, err := client.Connect()
if err != nil {
t.Fatal(err)
}

if db.featureSupported(featureCreateRoleSelfGrant) {
t.Skipf("Skip tests for unsuported feature %d in Postgres %s", featureCreateRoleSelfGrant, db.version)
}

// Create NON superuser role
if _, err = db.Exec("CREATE ROLE rds_srg LOGIN CREATEDB CREATEROLE PASSWORD 'rds_srg'"); err != nil {
t.Fatalf("could not create role for test user paramaters: %v", err)
}
defer func() {
_, _ = db.Exec("DROP ROLE rds_srg")
}()

provider := Provider()
provider.Configure(context.Background(), terraform.NewResourceConfigRaw(
map[string]interface{}{
"username": "rds_srg",
"password": "rds_srg",
},
))
}

func testAccPreCheck(t *testing.T) {
var host string
if host = os.Getenv("PGHOST"); host == "" {
Expand Down
13 changes: 11 additions & 2 deletions postgresql/resource_postgresql_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,17 @@ resource postgresql_database "test_db" {
resource.TestCheckResourceAttr("postgresql_database.test_db", "name", "test_db"),
resource.TestCheckResourceAttr("postgresql_database.test_db", "owner", "test_owner"),

// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false),
func(state *terraform.State) error {
connect, _ := config.NewClient("postgres").Connect()
if connect.featureSupported(featureCreateRoleSelfGrant) {
// in PG 16 all created roles have creator grant with admin option
checkUserMembership(t, dsn, config.Username, "test_owner", true)
} else {
// check if connected user does not have test_owner granted anymore.
checkUserMembership(t, dsn, config.Username, "test_owner", false)
}
return nil
},
),
},
},
Expand Down
Loading

0 comments on commit 6472ad1

Please sign in to comment.