-
Notifications
You must be signed in to change notification settings - Fork 27
[DPE-7500] Create catalog/database level roles #921
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 all commits
e1a14e0
23c1ea0
a5c6442
09c4a71
d778bba
873132e
0dc8d3d
1764971
fead5cd
2c0f822
c848782
e49e999
5724320
8da9ab5
e4bc8d2
8094e4f
2f204a9
0dd22ed
d453455
2fc6e5c
fea0148
1c5a911
6a083c5
16d6783
fe5ce8f
43493d4
1005f7e
c526616
5de77d0
ff5dd37
1d170ff
44beefa
883c4ba
4eb981b
8b85257
e669da3
17e7e4a
f1d3293
3aba882
e16567d
2c15212
f711479
1fed145
c8efa82
6cd2a85
e42e220
fbebe06
3ae3885
fb566b5
5f2328e
3deb576
c78e2ff
526bf2d
fd41021
fa1efa7
4084579
f3eceba
9721e91
7f98938
40c2051
d121c1f
71fb74f
dc5b01e
262dc2b
0848dcf
32f4f56
24605d9
4f2f0e2
32663cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,12 +110,13 @@ def _on_database_requested(self, event: DatabaseRequestedEvent) -> None: | |
| try: | ||
| # Creates the user and the database for this specific relation. | ||
| user = f"relation-{event.relation.id}" | ||
| password = new_password() | ||
| self.charm.postgresql.create_user(user, password, extra_user_roles=extra_user_roles) | ||
| plugins = self.charm.get_plugins() | ||
|
|
||
| self.charm.postgresql.create_database( | ||
| database, user, plugins=plugins, client_relations=self.charm.client_relations | ||
| self.charm.postgresql.create_database(database, plugins=plugins) | ||
|
|
||
| password = new_password() | ||
| self.charm.postgresql.create_user( | ||
| user, password, extra_user_roles=extra_user_roles, in_role=f"{database}_admin" | ||
| ) | ||
|
Comment on lines
+115
to
120
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. The order of the calls was changed here because the catalog/database level roles are created along with the database, and we need to pass the |
||
|
|
||
| # Share the credentials with the application. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
|
|
||
| import botocore | ||
| import psycopg2 | ||
| import pytest | ||
| import requests | ||
| import yaml | ||
| from juju.model import Model | ||
|
|
@@ -755,6 +756,63 @@ def check_connected_user( | |
| assert False, "No result returned from the query" | ||
|
|
||
|
|
||
| async def check_roles_and_their_permissions( | ||
| ops_test: OpsTest, relation_endpoint: str, database_name: str | ||
| ) -> None: | ||
| action = await ops_test.model.units[f"{DATA_INTEGRATOR_APP_NAME}/0"].run_action( | ||
| action_name="get-credentials" | ||
| ) | ||
| result = await action.wait() | ||
| data_integrator_credentials = result.results | ||
| username = data_integrator_credentials[relation_endpoint]["username"] | ||
| uris = data_integrator_credentials[relation_endpoint]["uris"] | ||
| connection = None | ||
| try: | ||
| connection = psycopg2.connect(uris) | ||
| connection.autocommit = True | ||
| with connection.cursor() as cursor: | ||
| logger.info( | ||
| "Checking that the relation user is automatically escalated to the database owner user" | ||
| ) | ||
| check_connected_user(cursor, username, f"{database_name}_owner") | ||
| logger.info("Creating a test table and inserting data") | ||
| cursor.execute("CREATE TABLE test_table (id INTEGER);") | ||
| logger.info("Inserting data into the test table") | ||
| cursor.execute("INSERT INTO test_table(id) VALUES(1);") | ||
| logger.info("Reading data from the test table") | ||
| cursor.execute("SELECT * FROM test_table;") | ||
| result = cursor.fetchall() | ||
| assert len(result) == 1, "The database owner user should be able to read the data" | ||
|
|
||
| logger.info("Checking that the database owner user can't create a database") | ||
| with pytest.raises(psycopg2.errors.InsufficientPrivilege): | ||
| cursor.execute(f"CREATE DATABASE {database_name}_2;") | ||
|
|
||
| logger.info("Checking that the relation user can't create a table") | ||
| cursor.execute("RESET ROLE;") | ||
| check_connected_user(cursor, username, username) | ||
| with pytest.raises(psycopg2.errors.InsufficientPrivilege): | ||
| cursor.execute("CREATE TABLE test_table_2 (id INTEGER);") | ||
| finally: | ||
| if connection is not None: | ||
| connection.close() | ||
|
|
||
| connection_string = f"host={data_integrator_credentials[relation_endpoint]['read-only-endpoints'].split(':')[0]} dbname={data_integrator_credentials[relation_endpoint]['database']} user={username} password={data_integrator_credentials[relation_endpoint]['password']}" | ||
| connection = None | ||
| try: | ||
| connection = psycopg2.connect(connection_string) | ||
| with connection.cursor() as cursor: | ||
| logger.info("Checking that the relation user can read data from the database") | ||
| check_connected_user(cursor, username, username, primary=False) | ||
| logger.info("Reading data from the test table") | ||
| cursor.execute("SELECT * FROM test_table;") | ||
| result = cursor.fetchall() | ||
| assert len(result) == 1, "The relation user should be able to read the data" | ||
| finally: | ||
| if connection is not None: | ||
| connection.close() | ||
|
|
||
|
|
||
| async def check_tls(ops_test: OpsTest, unit_name: str, enabled: bool) -> bool: | ||
| """Returns whether TLS is enabled on the specific PostgreSQL instance. | ||
|
|
||
|
|
@@ -918,6 +976,14 @@ async def primary_changed(ops_test: OpsTest, old_primary: str) -> bool: | |
| return primary != old_primary | ||
|
|
||
|
|
||
| def relations(ops_test: OpsTest, provider_app: str, requirer_app: str) -> list: | ||
| return [ | ||
| relation | ||
| for relation in ops_test.model.applications[provider_app].relations | ||
| if not relation.is_peer and relation.requires.application_name == requirer_app | ||
| ] | ||
|
Comment on lines
+979
to
+984
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. Way to check if the relation still exists (and avoid situations where we removed it and it's still alive when trying to re-relate). |
||
|
|
||
|
|
||
| async def restart_machine(ops_test: OpsTest, unit_name: str) -> None: | ||
| """Restart the machine where a unit run on. | ||
|
|
||
|
|
||
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.
Just renaming to be clear on which types of predefined roles we are creating at this moment (i.e. the ones introduced by #881).