diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 7e6a9d7631..2a12d378d0 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -35,7 +35,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 51 +LIBPATCH = 52 # Groups to distinguish HBA access ACCESS_GROUP_IDENTITY = "identity_access" @@ -208,6 +208,7 @@ def create_database( user: str, plugins: Optional[List[str]] = None, client_relations: Optional[List[Relation]] = None, + admin: bool = False, ) -> None: """Creates a new database and grant privileges to a user on it. @@ -216,6 +217,7 @@ def create_database( user: user that will have access to the database. plugins: extensions to enable in the new database. client_relations: current established client relations. + admin: if the user should be admin. """ plugins = plugins if plugins else [] client_relations = client_relations if client_relations else [] @@ -233,9 +235,14 @@ def create_database( ) ) for user_to_grant_access in [user, PERMISSIONS_GROUP_ADMIN, *self.system_users]: + regrant = "" + if ( + user_to_grant_access == user and admin + ) or user_to_grant_access == PERMISSIONS_GROUP_ADMIN: + regrant = "WITH GRANT OPTION" cursor.execute( - SQL("GRANT ALL PRIVILEGES ON DATABASE {} TO {};").format( - Identifier(database), Identifier(user_to_grant_access) + SQL("GRANT ALL PRIVILEGES ON DATABASE {} TO {}{};").format( + Identifier(database), Identifier(user_to_grant_access), SQL(regrant) ) ) relations_accessing_this_database = 0 diff --git a/src/relations/postgresql_provider.py b/src/relations/postgresql_provider.py index a828d046ae..336edf072e 100644 --- a/src/relations/postgresql_provider.py +++ b/src/relations/postgresql_provider.py @@ -106,7 +106,11 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: plugins = self.charm.get_plugins() self.charm.postgresql.create_database( - database, user, plugins=plugins, client_relations=self.charm.client_relations + database, + user, + plugins=plugins, + client_relations=self.charm.client_relations, + admin="admin" in extra_user_roles, ) # Share the credentials with the application. diff --git a/tests/integration/test_password_rotation.py b/tests/integration/test_password_rotation.py index 8684ab1394..9c68f31794 100644 --- a/tests/integration/test_password_rotation.py +++ b/tests/integration/test_password_rotation.py @@ -43,35 +43,45 @@ async def test_password_rotation(ops_test: OpsTest): # Change both passwords. await set_password(ops_test, password="test-password") - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", idle_period=30, timeout=1000 + ) new_superuser_password = await get_password(ops_test) assert superuser_password != new_superuser_password # For replication, generate a specific password and pass it to the action. new_replication_password = "test-password" await set_password(ops_test, username="replication", password=new_replication_password) - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", idle_period=30, timeout=1000 + ) assert new_replication_password == await get_password(ops_test, "replication") assert replication_password != new_replication_password # For monitoring, generate a specific password and pass it to the action. new_monitoring_password = "test-password" await set_password(ops_test, username="monitoring", password=new_monitoring_password) - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", idle_period=30, timeout=1000 + ) assert new_monitoring_password == await get_password(ops_test, "monitoring") assert monitoring_password != new_monitoring_password # For backup, generate a specific password and pass it to the action. new_backup_password = "test-password" await set_password(ops_test, username="backup", password=new_backup_password) - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", idle_period=30, timeout=1000 + ) assert new_backup_password == await get_password(ops_test, "backup") assert backup_password != new_backup_password # For rewind, generate a specific password and pass it to the action. new_rewind_password = "test-password" await set_password(ops_test, username="rewind", password=new_rewind_password) - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) + await ops_test.model.wait_for_idle( + apps=[APP_NAME], status="active", idle_period=30, timeout=1000 + ) assert new_rewind_password == await get_password(ops_test, "rewind") assert rewind_password != new_rewind_password diff --git a/tests/unit/test_postgresql.py b/tests/unit/test_postgresql.py index 24e863b57b..a1b4d913f8 100644 --- a/tests/unit/test_postgresql.py +++ b/tests/unit/test_postgresql.py @@ -93,6 +93,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(user), + SQL(""), SQL(";"), ]) ), @@ -102,6 +103,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(PERMISSIONS_GROUP_ADMIN), + SQL("WITH GRANT OPTION"), SQL(";"), ]) ), @@ -111,6 +113,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(BACKUP_USER), + SQL(""), SQL(";"), ]) ), @@ -120,6 +123,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(REPLICATION_USER), + SQL(""), SQL(";"), ]) ), @@ -129,6 +133,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(REWIND_USER), + SQL(""), SQL(";"), ]) ), @@ -138,6 +143,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(USER), + SQL(""), SQL(";"), ]) ), @@ -147,6 +153,7 @@ def test_create_database(harness): Identifier(database), SQL(" TO "), Identifier(MONITORING_USER), + SQL(""), SQL(";"), ]) ), diff --git a/tests/unit/test_postgresql_provider.py b/tests/unit/test_postgresql_provider.py index 1c1e1bd017..1309870d01 100644 --- a/tests/unit/test_postgresql_provider.py +++ b/tests/unit/test_postgresql_provider.py @@ -117,10 +117,7 @@ def test_on_database_requested(harness): database_relation = harness.model.get_relation(RELATION_NAME) client_relations = [database_relation] postgresql_mock.create_database.assert_called_once_with( - DATABASE, - user, - plugins=["pgaudit"], - client_relations=client_relations, + DATABASE, user, plugins=["pgaudit"], client_relations=client_relations, admin=False ) postgresql_mock.get_postgresql_version.assert_called_once()