-
Notifications
You must be signed in to change notification settings - Fork 1
[DPE-7302] Prefixes helpers #27
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
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 |
|---|---|---|
|
|
@@ -114,6 +114,10 @@ def __init__(self, message: Optional[str] = None): | |
| self.message = message | ||
|
|
||
|
|
||
| class PostgreSQLUpdateUserError(PostgreSQLBaseError): | ||
| """Exception raised when creating a user fails.""" | ||
|
|
||
|
|
||
| class PostgreSQLUndefinedHostError(PostgreSQLBaseError): | ||
| """Exception when host is not set.""" | ||
|
|
||
|
|
@@ -146,6 +150,10 @@ class PostgreSQLGetPostgreSQLVersionError(PostgreSQLBaseError): | |
| """Exception raised when retrieving PostgreSQL version fails.""" | ||
|
|
||
|
|
||
| class PostgreSQLListDatabasesError(PostgreSQLBaseError): | ||
| """Exception raised when retrieving the databases.""" | ||
|
|
||
|
|
||
| class PostgreSQLListAccessibleDatabasesForUserError(PostgreSQLBaseError): | ||
| """Exception raised when retrieving the accessible databases for a user fails.""" | ||
|
|
||
|
|
@@ -439,24 +447,36 @@ def _adjust_user_definition( | |
| Returns: | ||
| A tuple containing the adjusted user definition and a list of additional statements. | ||
| """ | ||
| db_roles, connect_statements = self._adjust_user_roles(user, roles, database) | ||
| if db_roles: | ||
| str_roles = [f'"{role}"' for role in db_roles] | ||
| user_definition += f" IN ROLE {', '.join(str_roles)}" | ||
| return user_definition, connect_statements | ||
|
|
||
| def _adjust_user_roles( | ||
|
Contributor
Author
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. Split off from |
||
| self, user: str, roles: Optional[List[str]], database: Optional[str] | ||
| ) -> Tuple[List[str], List[str]]: | ||
| """Adjusts the user definition to include additional statements. | ||
|
|
||
| Returns: | ||
| A tuple containing the adjusted user definition and a list of additional statements. | ||
| """ | ||
| db_roles = [] | ||
| connect_statements = [] | ||
| if database: | ||
| if roles is not None and not any( | ||
| True | ||
| for role in roles | ||
| if role in [ROLE_STATS, ROLE_READ, ROLE_DML, ROLE_BACKUP, ROLE_DBA] | ||
| role in [ROLE_STATS, ROLE_READ, ROLE_DML, ROLE_BACKUP, ROLE_DBA] for role in roles | ||
| ): | ||
| user_definition += f' IN ROLE "charmed_{database}_admin", "charmed_{database}_dml"' | ||
| db_roles.append(f"charmed_{database}_admin") | ||
| db_roles.append(f"charmed_{database}_dml") | ||
| else: | ||
| connect_statements.append( | ||
| SQL("GRANT CONNECT ON DATABASE {} TO {};").format( | ||
| Identifier(database), Identifier(user) | ||
| ) | ||
| ) | ||
| if roles is not None and any( | ||
| True | ||
| for role in roles | ||
| if role | ||
| role | ||
| in [ | ||
| ROLE_STATS, | ||
| ROLE_READ, | ||
|
|
@@ -466,14 +486,15 @@ def _adjust_user_definition( | |
| ROLE_ADMIN, | ||
| ROLE_DATABASES_OWNER, | ||
| ] | ||
| for role in roles | ||
| ): | ||
| for system_database in ["postgres", "template1"]: | ||
| connect_statements.append( | ||
| SQL("GRANT CONNECT ON DATABASE {} TO {};").format( | ||
| Identifier(system_database), Identifier(user) | ||
| ) | ||
| ) | ||
| return user_definition, connect_statements | ||
| return db_roles, connect_statements | ||
|
|
||
| def _process_extra_user_roles( | ||
| self, user: str, extra_user_roles: Optional[List[str]] = None | ||
|
|
@@ -1841,3 +1862,50 @@ def drop_hba_triggers(self) -> None: | |
| finally: | ||
| if connection: | ||
| connection.close() | ||
|
|
||
| def list_databases(self, prefix: Optional[str] = None) -> List[str]: | ||
| """List non-system databases starting with prefix.""" | ||
| prefix_stmt = ( | ||
| SQL(" AND datname LIKE {}").format(Literal(prefix + "%")) if prefix else SQL("") | ||
| ) | ||
| try: | ||
| with self._connect_to_database() as connection, connection.cursor() as cursor: | ||
| cursor.execute( | ||
| SQL( | ||
| "SELECT datname FROM pg_database WHERE datistemplate = false AND datname <>'postgres'{};" | ||
| ).format(prefix_stmt) | ||
| ) | ||
| return [row[0] for row in cursor.fetchall()] | ||
| except psycopg2.Error as e: | ||
| raise PostgreSQLListDatabasesError() from e | ||
| finally: | ||
| if connection: | ||
| connection.close() | ||
|
|
||
| def add_user_to_databases( | ||
| self, user: str, databases: List[str], extra_user_roles: Optional[List[str]] = None | ||
| ) -> None: | ||
|
Comment on lines
+1885
to
+1887
Contributor
Author
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. So we don't alter the user, just add roles and connect privs. |
||
| """Grant user access to database.""" | ||
| try: | ||
| roles, _ = self._process_extra_user_roles(user, extra_user_roles) | ||
| connect_stmt = [] | ||
| for database in databases: | ||
| db_roles, db_connect_stmt = self._adjust_user_roles(user, roles, database) | ||
| roles += db_roles | ||
| connect_stmt += db_connect_stmt | ||
| with self._connect_to_database() as connection, connection.cursor() as cursor: | ||
|
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. unrelated and out of curiosity, why not add commit control on the context manager, as a parameter of
Contributor
Author
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. Likely copy paste momentum. We should overhaul and move to |
||
| cursor.execute(SQL("RESET ROLE;")) | ||
| cursor.execute(SQL("BEGIN;")) | ||
| cursor.execute(SQL("SET LOCAL log_statement = 'none';")) | ||
| cursor.execute(SQL("COMMIT;")) | ||
|
|
||
| # Add extra user roles to the new user. | ||
| for role in roles: | ||
| cursor.execute( | ||
| SQL("GRANT {} TO {};").format(Identifier(role), Identifier(user)) | ||
| ) | ||
| for statement in connect_stmt: | ||
| cursor.execute(statement) | ||
| except psycopg2.Error as e: | ||
| logger.error(f"Failed to create user: {e}") | ||
| raise PostgreSQLUpdateUserError() from e | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.