Skip to content

Commit 6610871

Browse files
authored
[MISC] Add Pyright to linting (#1053)
* Initial pyright WIP * Pyright WIP * Pyright * Disable unit tests * Fixes * Reenable unit tests * Check local member for TLS * Revert postgresql prop * Revert async repl * Bring back some of the async changes * Add async exception * Fix unit_ip * Increase scale timeout
1 parent de009c7 commit 6610871

22 files changed

+619
-406
lines changed

lib/charms/postgresql_k8s/v1/postgresql.py

Lines changed: 112 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
from typing import Dict, List, Optional, Set, Tuple
2525

2626
import psycopg2
27-
from psycopg2.sql import SQL, Identifier, Literal
28-
2927
from constants import BACKUP_USER, SYSTEM_USERS
28+
from ops import ConfigData
29+
from psycopg2.sql import SQL, Identifier, Literal
3030

3131
# The unique Charmhub library identifier, never change it
3232
LIBID = "24ee217a54e840a598ff21a079c3e678"
@@ -82,123 +82,137 @@
8282
logger = logging.getLogger(__name__)
8383

8484

85-
class PostgreSQLAssignGroupError(Exception):
85+
class PostgreSQLBaseError(Exception):
86+
"""Base lib exception."""
87+
88+
message = None
89+
90+
91+
class PostgreSQLAssignGroupError(PostgreSQLBaseError):
8692
"""Exception raised when assigning to a group fails."""
8793

8894

89-
class PostgreSQLCreateDatabaseError(Exception):
95+
class PostgreSQLCreateDatabaseError(PostgreSQLBaseError):
9096
"""Exception raised when creating a database fails."""
9197

9298
def __init__(self, message: Optional[str] = None):
9399
super().__init__(message)
94100
self.message = message
95101

96102

97-
class PostgreSQLCreateGroupError(Exception):
103+
class PostgreSQLCreateGroupError(PostgreSQLBaseError):
98104
"""Exception raised when creating a group fails."""
99105

100106

101-
class PostgreSQLCreateUserError(Exception):
107+
class PostgreSQLCreateUserError(PostgreSQLBaseError):
102108
"""Exception raised when creating a user fails."""
103109

104110
def __init__(self, message: Optional[str] = None):
105111
super().__init__(message)
106112
self.message = message
107113

108114

109-
class PostgreSQLDatabasesSetupError(Exception):
115+
class PostgreSQLUndefinedHostError(PostgreSQLBaseError):
116+
"""Exception when host is not set."""
117+
118+
119+
class PostgreSQLUndefinedPasswordError(PostgreSQLBaseError):
120+
"""Exception when password is not set."""
121+
122+
123+
class PostgreSQLDatabasesSetupError(PostgreSQLBaseError):
110124
"""Exception raised when the databases setup fails."""
111125

112126

113-
class PostgreSQLDeleteUserError(Exception):
127+
class PostgreSQLDeleteUserError(PostgreSQLBaseError):
114128
"""Exception raised when deleting a user fails."""
115129

116130

117-
class PostgreSQLEnableDisableExtensionError(Exception):
131+
class PostgreSQLEnableDisableExtensionError(PostgreSQLBaseError):
118132
"""Exception raised when enabling/disabling an extension fails."""
119133

120134

121-
class PostgreSQLGetLastArchivedWALError(Exception):
135+
class PostgreSQLGetLastArchivedWALError(PostgreSQLBaseError):
122136
"""Exception raised when retrieving last archived WAL fails."""
123137

124138

125-
class PostgreSQLGetCurrentTimelineError(Exception):
139+
class PostgreSQLGetCurrentTimelineError(PostgreSQLBaseError):
126140
"""Exception raised when retrieving current timeline id for the PostgreSQL unit fails."""
127141

128142

129-
class PostgreSQLGetPostgreSQLVersionError(Exception):
143+
class PostgreSQLGetPostgreSQLVersionError(PostgreSQLBaseError):
130144
"""Exception raised when retrieving PostgreSQL version fails."""
131145

132146

133-
class PostgreSQLListAccessibleDatabasesForUserError(Exception):
147+
class PostgreSQLListAccessibleDatabasesForUserError(PostgreSQLBaseError):
134148
"""Exception raised when retrieving the accessible databases for a user fails."""
135149

136150

137-
class PostgreSQLListGroupsError(Exception):
151+
class PostgreSQLListGroupsError(PostgreSQLBaseError):
138152
"""Exception raised when retrieving PostgreSQL groups list fails."""
139153

140154

141-
class PostgreSQLListUsersError(Exception):
155+
class PostgreSQLListUsersError(PostgreSQLBaseError):
142156
"""Exception raised when retrieving PostgreSQL users list fails."""
143157

144158

145-
class PostgreSQLUpdateUserPasswordError(Exception):
159+
class PostgreSQLUpdateUserPasswordError(PostgreSQLBaseError):
146160
"""Exception raised when updating a user password fails."""
147161

148162

149-
class PostgreSQLDatabaseExistsError(Exception):
163+
class PostgreSQLCreatePredefinedRolesError(PostgreSQLBaseError):
164+
"""Exception raised when creating predefined roles."""
165+
166+
167+
class PostgreSQLDatabaseExistsError(PostgreSQLBaseError):
150168
"""Exception raised during database existence check."""
151169

152170

153-
class PostgreSQLTableExistsError(Exception):
171+
class PostgreSQLTableExistsError(PostgreSQLBaseError):
154172
"""Exception raised during table existence check."""
155173

156174

157-
class PostgreSQLIsTableEmptyError(Exception):
175+
class PostgreSQLIsTableEmptyError(PostgreSQLBaseError):
158176
"""Exception raised during table emptiness check."""
159177

160178

161-
class PostgreSQLCreatePublicationError(Exception):
179+
class PostgreSQLCreatePublicationError(PostgreSQLBaseError):
162180
"""Exception raised when creating PostgreSQL publication."""
163181

164182

165-
class PostgreSQLPublicationExistsError(Exception):
183+
class PostgreSQLPublicationExistsError(PostgreSQLBaseError):
166184
"""Exception raised during PostgreSQL publication existence check."""
167185

168186

169-
class PostgreSQLAlterPublicationError(Exception):
187+
class PostgreSQLAlterPublicationError(PostgreSQLBaseError):
170188
"""Exception raised when altering PostgreSQL publication."""
171189

172190

173-
class PostgreSQLDropPublicationError(Exception):
191+
class PostgreSQLDropPublicationError(PostgreSQLBaseError):
174192
"""Exception raised when dropping PostgreSQL publication."""
175193

176194

177-
class PostgreSQLCreateSubscriptionError(Exception):
195+
class PostgreSQLCreateSubscriptionError(PostgreSQLBaseError):
178196
"""Exception raised when creating PostgreSQL subscription."""
179197

180198

181-
class PostgreSQLSubscriptionExistsError(Exception):
199+
class PostgreSQLSubscriptionExistsError(PostgreSQLBaseError):
182200
"""Exception raised during PostgreSQL subscription existence check."""
183201

184202

185-
class PostgreSQLUpdateSubscriptionError(Exception):
203+
class PostgreSQLUpdateSubscriptionError(PostgreSQLBaseError):
186204
"""Exception raised when updating PostgreSQL subscription."""
187205

188206

189-
class PostgreSQLRefreshSubscriptionError(Exception):
207+
class PostgreSQLRefreshSubscriptionError(PostgreSQLBaseError):
190208
"""Exception raised when refreshing PostgreSQL subscription."""
191209

192210

193-
class PostgreSQLDropSubscriptionError(Exception):
211+
class PostgreSQLDropSubscriptionError(PostgreSQLBaseError):
194212
"""Exception raised when dropping PostgreSQL subscription."""
195213

196214

197-
class PostgreSQLCreatePredefinedRolesError(Exception):
198-
"""Exception raised when creating predefined roles."""
199-
200-
201-
class PostgreSQLGrantDatabasePrivilegesToUserError(Exception):
215+
class PostgreSQLGrantDatabasePrivilegesToUserError(PostgreSQLBaseError):
202216
"""Exception raised when granting database privileges to user."""
203217

204218

@@ -207,10 +221,10 @@ class PostgreSQL:
207221

208222
def __init__(
209223
self,
210-
primary_host: str,
211-
current_host: str,
224+
primary_host: Optional[str],
225+
current_host: Optional[str],
212226
user: str,
213-
password: str,
227+
password: Optional[str],
214228
database: str,
215229
system_users: Optional[List[str]] = None,
216230
):
@@ -255,6 +269,10 @@ def _connect_to_database(
255269
psycopg2 connection object.
256270
"""
257271
host = database_host if database_host is not None else self.primary_host
272+
if not host:
273+
raise PostgreSQLUndefinedHostError("Host not set")
274+
if not self.password:
275+
raise PostgreSQLUndefinedPasswordError("Password not set")
258276
connection = psycopg2.connect(
259277
f"dbname='{database if database else self.database}' user='{self.user}' host='{host}'"
260278
f"password='{self.password}' connect_timeout=1"
@@ -358,7 +376,11 @@ def create_user(
358376
# Separate roles and privileges from the provided extra user roles.
359377
roles = privileges = None
360378
if extra_user_roles:
361-
if len(extra_user_roles) > 2 and sorted(extra_user_roles) != [ROLE_ADMIN, "createdb", ACCESS_GROUP_RELATION]:
379+
if len(extra_user_roles) > 2 and sorted(extra_user_roles) != [
380+
ROLE_ADMIN,
381+
"createdb",
382+
ACCESS_GROUP_RELATION,
383+
]:
362384
extra_user_roles.remove(ACCESS_GROUP_RELATION)
363385
logger.error(
364386
"Invalid extra user roles: "
@@ -367,7 +389,17 @@ def create_user(
367389
)
368390
raise PostgreSQLCreateUserError(INVALID_EXTRA_USER_ROLE_BLOCKING_MESSAGE)
369391
valid_privileges, valid_roles = self.list_valid_privileges_and_roles()
370-
roles = [role for role in extra_user_roles if (user == BACKUP_USER or user in SYSTEM_USERS or role in valid_roles or role == ACCESS_GROUP_RELATION or role == "createdb")]
392+
roles = [
393+
role
394+
for role in extra_user_roles
395+
if (
396+
user == BACKUP_USER
397+
or user in SYSTEM_USERS
398+
or role in valid_roles
399+
or role == ACCESS_GROUP_RELATION
400+
or role == "createdb"
401+
)
402+
]
371403
if "createdb" in extra_user_roles:
372404
extra_user_roles.remove("createdb")
373405
roles.remove("createdb")
@@ -394,22 +426,43 @@ def create_user(
394426
user_definition = "ALTER ROLE {} "
395427
else:
396428
user_definition = "CREATE ROLE {} "
397-
user_definition += (
398-
f"WITH LOGIN{' SUPERUSER' if admin else ''}{' REPLICATION' if replication else ''} ENCRYPTED PASSWORD '{password}'"
399-
)
429+
user_definition += f"WITH LOGIN{' SUPERUSER' if admin else ''}{' REPLICATION' if replication else ''} ENCRYPTED PASSWORD '{password}'"
400430
connect_statements = []
401431
if database:
402-
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]):
403-
user_definition += f' IN ROLE "charmed_{database}_admin", "charmed_{database}_dml"'
432+
if roles is not None and not any(
433+
True
434+
for role in roles
435+
if role in [ROLE_STATS, ROLE_READ, ROLE_DML, ROLE_BACKUP, ROLE_DBA]
436+
):
437+
user_definition += (
438+
f' IN ROLE "charmed_{database}_admin", "charmed_{database}_dml"'
439+
)
404440
else:
405-
connect_statements.append(SQL("GRANT CONNECT ON DATABASE {} TO {};").format(
406-
Identifier(database), Identifier(user)
407-
))
408-
if roles is not None and any(True for role in roles if role in [ROLE_STATS, ROLE_READ, ROLE_DML, ROLE_BACKUP, ROLE_DBA, ROLE_ADMIN, ROLE_DATABASES_OWNER]):
441+
connect_statements.append(
442+
SQL("GRANT CONNECT ON DATABASE {} TO {};").format(
443+
Identifier(database), Identifier(user)
444+
)
445+
)
446+
if roles is not None and any(
447+
True
448+
for role in roles
449+
if role
450+
in [
451+
ROLE_STATS,
452+
ROLE_READ,
453+
ROLE_DML,
454+
ROLE_BACKUP,
455+
ROLE_DBA,
456+
ROLE_ADMIN,
457+
ROLE_DATABASES_OWNER,
458+
]
459+
):
409460
for system_database in ["postgres", "template1"]:
410-
connect_statements.append(SQL("GRANT CONNECT ON DATABASE {} TO {};").format(
411-
Identifier(system_database), Identifier(user)
412-
))
461+
connect_statements.append(
462+
SQL("GRANT CONNECT ON DATABASE {} TO {};").format(
463+
Identifier(system_database), Identifier(user)
464+
)
465+
)
413466
if can_create_database:
414467
user_definition += " CREATEDB"
415468
if privileges:
@@ -470,7 +523,7 @@ def create_predefined_instance_roles(self) -> None:
470523
],
471524
ROLE_ADMIN: [
472525
f"CREATE ROLE {ROLE_ADMIN} NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOLOGIN IN ROLE {ROLE_DML}",
473-
]
526+
],
474527
}
475528

476529
try:
@@ -961,7 +1014,6 @@ def list_existing_roles(self) -> Set[str]:
9611014
cursor.execute("SELECT rolname FROM pg_roles;")
9621015
return {role[0] for role in cursor.fetchall() if role[0]}
9631016

964-
9651017
def list_valid_privileges_and_roles(self) -> Tuple[Set[str], Set[str]]:
9661018
"""Returns two sets with valid privileges and roles.
9671019
@@ -1208,24 +1260,26 @@ def set_up_predefined_catalog_roles_function(self) -> None:
12081260
try:
12091261
for database in self._get_existing_databases():
12101262
with self._connect_to_database(
1211-
database=database
1263+
database=database
12121264
) as connection, connection.cursor() as cursor:
12131265
cursor.execute(SQL(function_creation_statement))
12141266
cursor.execute(
12151267
SQL("ALTER FUNCTION set_up_predefined_catalog_roles OWNER TO operator;")
12161268
)
12171269
cursor.execute(
1218-
SQL("REVOKE EXECUTE ON FUNCTION set_up_predefined_catalog_roles FROM PUBLIC;")
1270+
SQL(
1271+
"REVOKE EXECUTE ON FUNCTION set_up_predefined_catalog_roles FROM PUBLIC;"
1272+
)
12191273
)
12201274
cursor.execute(
12211275
SQL(
12221276
"GRANT EXECUTE ON FUNCTION set_up_predefined_catalog_roles TO {};"
12231277
).format(Identifier(ROLE_DATABASES_OWNER))
12241278
)
12251279
cursor.execute(
1226-
SQL(
1227-
"REVOKE CREATE ON DATABASE {} FROM {};"
1228-
).format(Identifier("template1"), Identifier(ROLE_DATABASES_OWNER))
1280+
SQL("REVOKE CREATE ON DATABASE {} FROM {};").format(
1281+
Identifier("template1"), Identifier(ROLE_DATABASES_OWNER)
1282+
)
12291283
)
12301284
except psycopg2.Error as e:
12311285
logger.error(f"Failed to set up predefined catalog roles function: {e}")
@@ -1571,7 +1625,7 @@ def build_postgresql_group_map(group_map: Optional[str]) -> List[Tuple]:
15711625

15721626
@staticmethod
15731627
def build_postgresql_parameters(
1574-
config_options: dict, available_memory: int, limit_memory: Optional[int] = None
1628+
config_options: ConfigData, available_memory: int, limit_memory: Optional[int] = None
15751629
) -> Optional[dict]:
15761630
"""Builds the PostgreSQL parameters.
15771631

0 commit comments

Comments
 (0)