Skip to content

Commit 85f1024

Browse files
authored
Toggle plugins in one go (canonical#322)
1 parent c40b489 commit 85f1024

File tree

4 files changed

+20
-37
lines changed

4 files changed

+20
-37
lines changed

lib/charms/postgresql_k8s/v0/postgresql.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
# Increment this PATCH version before using `charmcraft publish-lib` or reset
3434
# to 0 if you are raising the major API version
35-
LIBPATCH = 19
35+
LIBPATCH = 20
3636

3737
INVALID_EXTRA_USER_ROLE_BLOCKING_MESSAGE = "invalid role(s) for extra user roles"
3838

@@ -172,8 +172,7 @@ def create_database(self, database: str, user: str, plugins: List[str] = []) ->
172172
raise PostgreSQLCreateDatabaseError()
173173

174174
# Enable preset extensions
175-
for plugin in plugins:
176-
self.enable_disable_extension(plugin, True, database)
175+
self.enable_disable_extensions({plugin: True for plugin in plugins}, database)
177176

178177
def create_user(
179178
self, user: str, password: str = None, admin: bool = False, extra_user_roles: str = None
@@ -270,22 +269,16 @@ def delete_user(self, user: str) -> None:
270269
logger.error(f"Failed to delete user: {e}")
271270
raise PostgreSQLDeleteUserError()
272271

273-
def enable_disable_extension(self, extension: str, enable: bool, database: str = None) -> None:
272+
def enable_disable_extensions(self, extensions: Dict[str, bool], database: str = None) -> None:
274273
"""Enables or disables a PostgreSQL extension.
275274
276275
Args:
277-
extension: the name of the extensions.
278-
enable: whether the extension should be enabled or disabled.
276+
extensions: the name of the extensions.
279277
database: optional database where to enable/disable the extension.
280278
281279
Raises:
282280
PostgreSQLEnableDisableExtensionError if the operation fails.
283281
"""
284-
statement = (
285-
f"CREATE EXTENSION IF NOT EXISTS {extension};"
286-
if enable
287-
else f"DROP EXTENSION IF EXISTS {extension};"
288-
)
289282
connection = None
290283
try:
291284
if database is not None:
@@ -301,7 +294,12 @@ def enable_disable_extension(self, extension: str, enable: bool, database: str =
301294
with self._connect_to_database(
302295
database=database
303296
) as connection, connection.cursor() as cursor:
304-
cursor.execute(statement)
297+
for extension, enable in extensions.items():
298+
cursor.execute(
299+
f"CREATE EXTENSION IF NOT EXISTS {extension};"
300+
if enable
301+
else f"DROP EXTENSION IF EXISTS {extension};"
302+
)
305303
except psycopg2.errors.UniqueViolation:
306304
pass
307305
except psycopg2.Error:

src/charm.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -552,24 +552,22 @@ def enable_disable_extensions(self, database: str = None) -> None:
552552
database: optional database where to enable/disable the extension.
553553
"""
554554
original_status = self.unit.status
555+
extensions = {}
556+
# collect extensions
555557
plugins_exception = {"uuid_ossp": '"uuid-ossp"'}
556558
for plugin in self.config.plugin_keys():
557559
enable = self.config[plugin]
558560

559561
# Enable or disable the plugin/extension.
560562
extension = "_".join(plugin.split("_")[1:-1])
561-
if extension in plugins_exception:
562-
extension = plugins_exception[extension]
563-
self.unit.status = WaitingStatus(
564-
f"{'Enabling' if enable else 'Disabling'} {extension}"
565-
)
566-
try:
567-
self.postgresql.enable_disable_extension(extension, enable, database)
568-
except PostgreSQLEnableDisableExtensionError as e:
569-
logger.exception(
570-
f"failed to {'enable' if enable else 'disable'} {extension} plugin: %s", str(e)
571-
)
572-
self.unit.status = original_status
563+
extension = plugins_exception.get(extension, extension)
564+
extensions[extension] = enable
565+
self.unit.status = WaitingStatus("Updating extensions")
566+
try:
567+
self.postgresql.enable_disable_extensions(extensions, database)
568+
except PostgreSQLEnableDisableExtensionError as e:
569+
logger.exception("failed to change plugins: %s", str(e))
570+
self.unit.status = original_status
573571

574572
def _add_members(self, event) -> None:
575573
"""Add new cluster members.

src/relations/db.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,6 @@ def set_up_relation(self, relation: Relation) -> bool:
152152

153153
self.charm.postgresql.create_database(database, user, plugins=plugins)
154154

155-
# Enable/disable extensions in the new database.
156-
self.charm.enable_disable_extensions(database)
157-
158155
# Build the primary's connection string.
159156
primary = str(
160157
ConnectionString(

tests/unit/test_db.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,12 @@ def test_get_extensions(self):
183183
)
184184

185185
@patch("relations.db.DbProvides._update_unit_status")
186-
@patch("charm.PostgresqlOperatorCharm.enable_disable_extensions")
187186
@patch("relations.db.new_password", return_value="test-password")
188187
@patch("relations.db.DbProvides._get_extensions")
189188
def test_set_up_relation(
190189
self,
191190
_get_extensions,
192191
_new_password,
193-
_enable_disable_extensions,
194192
_update_unit_status,
195193
):
196194
with patch.object(PostgresqlOperatorCharm, "postgresql", Mock()) as postgresql_mock:
@@ -228,7 +226,6 @@ def test_set_up_relation(
228226
self.assertFalse(self.harness.charm.legacy_db_relation.set_up_relation(relation))
229227
postgresql_mock.create_user.assert_not_called()
230228
postgresql_mock.create_database.assert_not_called()
231-
_enable_disable_extensions.assert_not_called()
232229
postgresql_mock.get_postgresql_version.assert_not_called()
233230
_update_unit_status.assert_not_called()
234231

@@ -244,7 +241,6 @@ def test_set_up_relation(
244241
user = f"relation_id_{self.rel_id}"
245242
postgresql_mock.create_user.assert_called_once_with(user, "test-password", False)
246243
postgresql_mock.create_database.assert_called_once_with(DATABASE, user, plugins=[])
247-
_enable_disable_extensions.assert_called_once()
248244
self.assertEqual(postgresql_mock.get_postgresql_version.call_count, 2)
249245
_update_unit_status.assert_called_once()
250246
expected_data = {
@@ -271,7 +267,6 @@ def test_set_up_relation(
271267
# provided only in the unit databag.
272268
postgresql_mock.create_user.reset_mock()
273269
postgresql_mock.create_database.reset_mock()
274-
_enable_disable_extensions.reset_mock()
275270
postgresql_mock.get_postgresql_version.reset_mock()
276271
_update_unit_status.reset_mock()
277272
with self.harness.hooks_disabled():
@@ -289,7 +284,6 @@ def test_set_up_relation(
289284
self.assertTrue(self.harness.charm.legacy_db_relation.set_up_relation(relation))
290285
postgresql_mock.create_user.assert_called_once_with(user, "test-password", False)
291286
postgresql_mock.create_database.assert_called_once_with(DATABASE, user, plugins=[])
292-
_enable_disable_extensions.assert_called_once()
293287
self.assertEqual(postgresql_mock.get_postgresql_version.call_count, 2)
294288
_update_unit_status.assert_called_once()
295289
self.assertEqual(self.harness.get_relation_data(self.rel_id, self.app), expected_data)
@@ -299,7 +293,6 @@ def test_set_up_relation(
299293
# Assert that the correct calls were made when the database name is not provided.
300294
postgresql_mock.create_user.reset_mock()
301295
postgresql_mock.create_database.reset_mock()
302-
_enable_disable_extensions.reset_mock()
303296
postgresql_mock.get_postgresql_version.reset_mock()
304297
_update_unit_status.reset_mock()
305298
with self.harness.hooks_disabled():
@@ -312,7 +305,6 @@ def test_set_up_relation(
312305
self.assertFalse(self.harness.charm.legacy_db_relation.set_up_relation(relation))
313306
postgresql_mock.create_user.assert_not_called()
314307
postgresql_mock.create_database.assert_not_called()
315-
_enable_disable_extensions.assert_not_called()
316308
postgresql_mock.get_postgresql_version.assert_not_called()
317309
_update_unit_status.assert_not_called()
318310
# No data is set in the databags by the database.
@@ -329,7 +321,6 @@ def test_set_up_relation(
329321
)
330322
self.assertFalse(self.harness.charm.legacy_db_relation.set_up_relation(relation))
331323
postgresql_mock.create_database.assert_not_called()
332-
_enable_disable_extensions.assert_not_called()
333324
postgresql_mock.get_postgresql_version.assert_not_called()
334325
_update_unit_status.assert_not_called()
335326
self.assertIsInstance(self.harness.model.unit.status, BlockedStatus)
@@ -340,7 +331,6 @@ def test_set_up_relation(
340331
# BlockedStatus due to a PostgreSQLCreateDatabaseError.
341332
self.harness.charm.unit.status = ActiveStatus()
342333
self.assertFalse(self.harness.charm.legacy_db_relation.set_up_relation(relation))
343-
_enable_disable_extensions.assert_not_called()
344334
postgresql_mock.get_postgresql_version.assert_not_called()
345335
_update_unit_status.assert_not_called()
346336
self.assertIsInstance(self.harness.model.unit.status, BlockedStatus)

0 commit comments

Comments
 (0)