-
Notifications
You must be signed in to change notification settings - Fork 258
fix: ALL implicit privileges equality check #339
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
Changes from 4 commits
09a9f30
edacad1
e3b92a0
add228c
f58fbb3
8dfcf90
db54bfc
54fc593
c64e956
a091370
30d4b45
d288aaf
55875e9
0393157
c35441d
4f65139
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package postgresql | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
@@ -17,3 +18,74 @@ func TestFindStringSubmatchMap(t *testing.T) { | |
}, | ||
) | ||
} | ||
|
||
func TestArePrivilegesEqual(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool 👍 |
||
|
||
type PrivilegesTestObject struct { | ||
d *schema.ResourceData | ||
granted *schema.Set | ||
wanted *schema.Set | ||
assertion bool | ||
} | ||
|
||
tt := []PrivilegesTestObject{ | ||
{ | ||
buildResourceData("database", t), | ||
buildPrivilegesSet("CONNECT", "CREATE", "TEMPORARY"), | ||
all(), | ||
true, | ||
}, | ||
{ | ||
buildResourceData("database", t), | ||
buildPrivilegesSet("CREATE", "USAGE"), | ||
buildPrivilegesSet("USAGE"), | ||
false, | ||
}, | ||
{ | ||
buildResourceData("table", t), | ||
buildPrivilegesSet("SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER"), | ||
all(), | ||
true, | ||
}, | ||
{ | ||
buildResourceData("table", t), | ||
buildPrivilegesSet("SELECT"), | ||
buildPrivilegesSet("SELECT, INSERT"), | ||
false, | ||
}, | ||
{ | ||
buildResourceData("schema", t), | ||
buildPrivilegesSet("CREATE", "USAGE"), | ||
all(), | ||
true, | ||
}, | ||
{ | ||
buildResourceData("schema", t), | ||
buildPrivilegesSet("CREATE"), | ||
all(), | ||
false, | ||
}, | ||
} | ||
|
||
for _, configuration := range tt { | ||
equal := arePrivilegesEqual(configuration.granted, configuration.wanted, configuration.d) | ||
assert.Equal(t, configuration.assertion, equal) | ||
} | ||
} | ||
|
||
func buildPrivilegesSet(grants ...interface{}) *schema.Set { | ||
return schema.NewSet(schema.HashString, grants) | ||
} | ||
|
||
func all() *schema.Set { | ||
return buildPrivilegesSet("ALL") | ||
} | ||
|
||
func buildResourceData(objectType string, t *testing.T) *schema.ResourceData { | ||
var testSchema = map[string]*schema.Schema{ | ||
"object_type": {Type: schema.TypeString}, | ||
} | ||
m := make(map[string]interface{}) | ||
m["object_type"] = objectType | ||
return schema.TestResourceDataRaw(t, testSchema, m) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -268,8 +268,12 @@ func readRoleDefaultPrivileges(txn *sql.Tx, d *schema.ResourceData) error { | |
} | ||
|
||
privilegesSet := pgArrayToSet(privileges) | ||
d.Set("privileges", privilegesSet) | ||
d.SetId(generateDefaultPrivilegesID(d)) | ||
privilegesEqual := arePrivilegesEqual(privilegesSet, d.Get("privileges").(*schema.Set), d) | ||
|
||
if !privilegesEqual { | ||
d.Set("privileges", privilegesSet) | ||
d.SetId(generateDefaultPrivilegesID(d)) | ||
|
||
} | ||
|
||
return nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -108,7 +108,9 @@ func resourcePostgreSQLGrantRead(db *DBConnection, d *schema.ResourceData) error | |||||
if err := validateFeatureSupport(db, d); err != nil { | ||||||
return fmt.Errorf("feature is not supported: %v", err) | ||||||
} | ||||||
|
||||||
if true { | ||||||
//return fmt.Errorf("hello world! %v", "you") | ||||||
} | ||||||
talbx marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
exists, err := checkRoleDBSchemaExists(db.client, d) | ||||||
if err != nil { | ||||||
return err | ||||||
|
@@ -269,8 +271,12 @@ WHERE grantee = $2 | |||||
if err := txn.QueryRow(query, dbName, roleOID).Scan(&privileges); err != nil { | ||||||
return fmt.Errorf("could not read privileges for database %s: %w", dbName, err) | ||||||
} | ||||||
|
||||||
d.Set("privileges", pgArrayToSet(privileges)) | ||||||
granted := pgArrayToSet(privileges) | ||||||
wanted := d.Get("privileges").(*schema.Set) | ||||||
equal := arePrivilegesEqual(granted, wanted, d) | ||||||
if !equal { | ||||||
return d.Set("privileges", wanted) | ||||||
|
return d.Set("privileges", wanted) | |
return d.Set("privileges", granted) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not quite sure about that. We check whats on the DB...
if the state on the DB does not equal whats requested via terraform, we want to set the privileges that are requested. granted
is what we already have. this would then probably also apply to your other comment.
Also, that would be strange because that would be a fundamental bug in the "feature". Since i tested the changes with a database locally and had great success with the former implementation, I would be very much surprised if this was wrong all the way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the only thing that is weird to me right now is the fact, that I fetch the required privileges from the resourcedata and then put it back there again. this call is quite superflous but still won't hurt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we want to set the privileges that are requested. granted is what we already have.
Indeed, but that's not exactly how this function works.
The goal of a resource read function (in this case resourcePostgreSQLGrantRead
) is to refresh the Terraform state with the current status of what's in Postgres.
Then Terraform will compare the resource as it's defined in your code with how it is in the state (so in Postgres).
So the goal of this line is to set the privileges as it is in the dabase so it will be compared with what's defined in you resource definition.
Since i tested the changes with a database locally and had great success with the former implementation
It's because you haven't tested all the use cases (if I dare 😅 )
You think you fully fix that because there's no more diff in terraform plan
compared to before, but actually there will now never be any diff because you say that the current state in the database is what's defined in your code, so Terraform will always say that everything is already correct.
Easy to demonstrate with this simple code:
resource "postgresql_database" "test" {
name = "test_db"
}
resource "postgresql_role" "test" {
name = "test"
}
resource "postgresql_grant" "db_all" {
database = postgresql_database.test.name
role = postgresql_role.test.name
object_type = "database"
privileges = ["ALL"]
}
that you can apply:
terraform apply
Then, you manually remove a permission in Postgres:
$ psql -c "revoke connect ON database test_db from test "
REVOKE
And next terraform plan
will not show any diff when it should say that it needs to fix the permissions.
If I rebuild my provider with the suggestion I did above (set granted
instead of wanted), if I manually remove a permission from the database, I will have this plan:
$ terraform plan
[...]
Terraform will perform the following actions:
# postgresql_grant.db_all must be replaced
-/+ resource "postgresql_grant" "db_all" {
~ id = "test_test_db_database" -> (known after apply)
~ privileges = [ # forces replacement
- "CREATE",
- "TEMPORARY",
+ "ALL",
]
# (4 unchanged attributes hidden)
}
And once applied, thanks to your fix, there will not be any diff in the next plan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh!
There was an error while loading. Please reload this page.