Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,98 @@ options:
default: false
type: boolean
description: Enable unaccent extension
plugin_bloom_enable:
default: false
type: boolean
description: Enable bloom extension
plugin_btree_gin_enable:
default: false
type: boolean
description: Enable btree_gin extension
plugin_btree_gist_enable:
default: false
type: boolean
description: Enable btree_gist extension
plugin_cube_enable:
default: false
type: boolean
description: Enable cube extension
plugin_dict_int_enable:
default: false
type: boolean
description: Enable dict_int extension
plugin_dict_xsyn_enable:
default: false
type: boolean
description: Enable dict_xsyn extension
plugin_earthdistance_enable:
default: false
type: boolean
description: Enable earthdistance extension
plugin_fuzzystrmatch_enable:
default: false
type: boolean
description: Enable fuzzystrmatch extension
plugin_intarray_enable:
default: false
type: boolean
description: Enable intarray extension
plugin_isn_enable:
default: false
type: boolean
description: Enable isn extension
plugin_lo_enable:
default: false
type: boolean
description: Enable lo extension
plugin_ltree_enable:
default: false
type: boolean
description: Enable ltree extension
plugin_old_snapshot_enable:
default: false
type: boolean
description: Enable old_snapshot extension
plugin_pg_freespacemap_enable:
default: false
type: boolean
description: Enable pg_freespacemap extension
plugin_pgrowlocks_enable:
default: false
type: boolean
description: Enable pgrowlocks extension
plugin_pgstattuple_enable:
default: false
type: boolean
description: Enable pgstattuple extension
plugin_pg_visibility_enable:
default: false
type: boolean
description: Enable pg_visibility extension
plugin_seg_enable:
default: false
type: boolean
description: Enable seg extension
plugin_tablefunc_enable:
default: false
type: boolean
description: Enable tablefunc extension
plugin_tcn_enable:
default: false
type: boolean
description: Enable tcn extension
plugin_tsm_system_rows_enable:
default: false
type: boolean
description: Enable tsm_system_rows extension
plugin_tsm_system_time_enable:
default: false
type: boolean
description: Enable tsm_system_time extension
plugin_uuid_ossp_enable:
default: false
type: boolean
description: Enable uuid_ossp extension
profile:
description: |
Profile representing the scope of deployment, and used to tune resource allocation.
Expand Down
3 changes: 3 additions & 0 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,13 +948,16 @@ def enable_disable_extensions(self, database: str = None) -> None:
database: optional database where to enable/disable the extension.
"""
original_status = self.unit.status
plugins_exception = {"uuid_ossp": '"uuid-ossp"'}
extensions = {}
# collect extensions
for plugin in self.config.plugin_keys():
enable = self.config[plugin]

# Enable or disable the plugin/extension.
extension = "_".join(plugin.split("_")[1:-1])
if extension in plugins_exception:
extension = plugins_exception[extension]
extensions[extension] = enable
self.unit.status = WaitingStatus("Updating extensions")
try:
Expand Down
23 changes: 23 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,29 @@ class CharmConfig(BaseConfigModel):
plugin_pg_trgm_enable: bool
plugin_plpython3u_enable: bool
plugin_unaccent_enable: bool
plugin_bloom_enable: bool
plugin_btree_gin_enable: bool
plugin_btree_gist_enable: bool
plugin_cube_enable: bool
plugin_dict_int_enable: bool
plugin_dict_xsyn_enable: bool
plugin_earthdistance_enable: bool
plugin_fuzzystrmatch_enable: bool
plugin_intarray_enable: bool
plugin_isn_enable: bool
plugin_lo_enable: bool
plugin_ltree_enable: bool
plugin_old_snapshot_enable: bool
plugin_pg_freespacemap_enable: bool
plugin_pgrowlocks_enable: bool
plugin_pgstattuple_enable: bool
plugin_pg_visibility_enable: bool
plugin_seg_enable: bool
plugin_tablefunc_enable: bool
plugin_tcn_enable: bool
plugin_tsm_system_rows_enable: bool
plugin_tsm_system_time_enable: bool
plugin_uuid_ossp_enable: bool
request_date_style: Optional[str]
request_standard_conforming_strings: Optional[bool]
request_time_zone: Optional[str]
Expand Down
129 changes: 79 additions & 50 deletions tests/integration/test_plugins.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like in k8s, I think it's better to have a single mapping and loop over it in config and test assertions.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@
PG_TRGM_EXTENSION_STATEMENT = "SELECT word_similarity('word', 'two words');"
PLPYTHON3U_EXTENSION_STATEMENT = 'CREATE FUNCTION plpython_test() RETURNS varchar[] AS $$ return "hello" $$ LANGUAGE plpython3u;'
UNACCENT_EXTENSION_STATEMENT = "SELECT ts_lexize('unaccent','Hôtel');"
BLOOM_EXTENSION_STATEMENT = (
"CREATE TABLE tbloom_test (i int);CREATE INDEX btreeidx ON tbloom_test USING bloom (i);"
)
BTREEGIN_EXTENSION_STATEMENT = "CREATE TABLE btree_gin_test (a int4);CREATE INDEX btreeginidx ON btree_gin_test USING GIN (a);"
BTREEGIST_EXTENSION_STATEMENT = "CREATE TABLE btree_gist_test (a int4);CREATE INDEX btreegistidx ON btree_gist_test USING GIST (a);"
CUBE_EXTENSION_STATEMENT = "SELECT cube_inter('(0,-1),(1,1)', '(-2),(2)');"
DICTINT_EXTENSION_STATEMENT = "SELECT ts_lexize('intdict', '12345678');"
DICTXSYN_EXTENSION_STATEMENT = "SELECT ts_lexize('xsyn', 'word');"
EARTHDISTANCE_EXTENSION_STATEMENT = "SELECT earth_distance(ll_to_earth(-81.3927381, 30.2918842),ll_to_earth(-87.6473133, 41.8853881));"
FUZZYSTRMATCH_EXTENSION_STATEMENT = "SELECT soundex('hello world!');"
INTARRAY_EXTENSION_STATEMENT = "CREATE TABLE intarray_test (mid INT PRIMARY KEY, sections INT[]);SELECT intarray_test.mid FROM intarray_test WHERE intarray_test.sections @> '{1,2}';"
ISN_EXTENSION_STATEMENT = "SELECT isbn('978-0-393-04002-9');"
LO_EXTENSION_STATEMENT = "CREATE TABLE lo_test (value lo);"
LTREE_EXTENSION_STATEMENT = "CREATE TABLE ltree_test (path ltree);"
OLD_SNAPSHOT_EXTENSION_STATEMENT = "SELECT * from pg_old_snapshot_time_mapping();"
PG_FREESPACEMAP_EXTENSION_STATEMENT = (
"CREATE TABLE pg_freespacemap_test (i int);SELECT * FROM pg_freespace('pg_freespacemap_test');"
)
PGROWLOCKS_EXTENSION_STATEMENT = (
"CREATE TABLE pgrowlocks_test (i int);SELECT * FROM pgrowlocks('pgrowlocks_test');"
)
PGSTATTUPLE_EXTENSION_STATEMENT = "SELECT * FROM pgstattuple('pg_catalog.pg_proc');"
PG_VISIBILITY_EXTENSION_STATEMENT = "CREATE TABLE pg_visibility_test (i int);SELECT * FROM pg_visibility('pg_visibility_test'::regclass);"
SEG_EXTENSION_STATEMENT = "SELECT '10(+-)1'::seg as seg;"
TABLEFUNC_EXTENSION_STATEMENT = "SELECT * FROM normal_rand(1000, 5, 3);"
TCN_EXTENSION_STATEMENT = "CREATE TABLE tcn_test (i int);CREATE TRIGGER tcn_test_idx AFTER INSERT OR UPDATE OR DELETE ON tcn_test FOR EACH ROW EXECUTE FUNCTION TRIGGERED_CHANGE_NOTIFICATION();"
TSM_SYSTEM_ROWS_EXTENSION_STATEMENT = "CREATE TABLE tsm_system_rows_test (i int);SELECT * FROM tsm_system_rows_test TABLESAMPLE SYSTEM_ROWS(100);"
TSM_SYSTEM_TIME_EXTENSION_STATEMENT = "CREATE TABLE tsm_system_time_test (i int);SELECT * FROM tsm_system_time_test TABLESAMPLE SYSTEM_TIME(1000);"
UUID_OSSP_EXTENSION_STATEMENT = "SELECT uuid_nil();"


@pytest.mark.abort_on_fail
Expand All @@ -40,72 +69,72 @@ async def test_plugins(ops_test: OpsTest) -> None:
)
await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active", timeout=1000)

sql_tests = {
"plugin_citext_enable": CITEXT_EXTENSION_STATEMENT,
"plugin_debversion_enable": DEBVERSION_EXTENSION_STATEMENT,
"plugin_hstore_enable": HSTORE_EXTENSION_STATEMENT,
"plugin_pg_trgm_enable": PG_TRGM_EXTENSION_STATEMENT,
"plugin_plpython3u_enable": PLPYTHON3U_EXTENSION_STATEMENT,
"plugin_unaccent_enable": UNACCENT_EXTENSION_STATEMENT,
"plugin_bloom_enable": BLOOM_EXTENSION_STATEMENT,
"plugin_btree_gin_enable": BTREEGIN_EXTENSION_STATEMENT,
"plugin_btree_gist_enable": BTREEGIST_EXTENSION_STATEMENT,
"plugin_cube_enable": CUBE_EXTENSION_STATEMENT,
"plugin_dict_int_enable": DICTINT_EXTENSION_STATEMENT,
"plugin_dict_xsyn_enable": DICTXSYN_EXTENSION_STATEMENT,
"plugin_earthdistance_enable": EARTHDISTANCE_EXTENSION_STATEMENT,
"plugin_fuzzystrmatch_enable": FUZZYSTRMATCH_EXTENSION_STATEMENT,
"plugin_intarray_enable": INTARRAY_EXTENSION_STATEMENT,
"plugin_isn_enable": ISN_EXTENSION_STATEMENT,
"plugin_lo_enable": LO_EXTENSION_STATEMENT,
"plugin_ltree_enable": LTREE_EXTENSION_STATEMENT,
"plugin_old_snapshot_enable": OLD_SNAPSHOT_EXTENSION_STATEMENT,
"plugin_pg_freespacemap_enable": PG_FREESPACEMAP_EXTENSION_STATEMENT,
"plugin_pgrowlocks_enable": PGROWLOCKS_EXTENSION_STATEMENT,
"plugin_pgstattuple_enable": PGSTATTUPLE_EXTENSION_STATEMENT,
"plugin_pg_visibility_enable": PG_VISIBILITY_EXTENSION_STATEMENT,
"plugin_seg_enable": SEG_EXTENSION_STATEMENT,
"plugin_tablefunc_enable": TABLEFUNC_EXTENSION_STATEMENT,
"plugin_tcn_enable": TCN_EXTENSION_STATEMENT,
"plugin_tsm_system_rows_enable": TSM_SYSTEM_ROWS_EXTENSION_STATEMENT,
"plugin_tsm_system_time_enable": TSM_SYSTEM_TIME_EXTENSION_STATEMENT,
"plugin_uuid_ossp_enable": UUID_OSSP_EXTENSION_STATEMENT,
}

def enable_disable_config(enabled: False):
config = {}
for plugin in sql_tests.keys():
config[plugin] = f"{enabled}"
return config

# Check that the available plugins are disabled.
primary = await get_primary(ops_test, f"{DATABASE_APP_NAME}/0")
password = await get_password(ops_test, primary)
address = get_unit_address(ops_test, primary)

config = enable_disable_config(False)
await ops_test.model.applications[DATABASE_APP_NAME].set_config(config)
await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active")

logger.info("checking that the plugins are disabled")
with db_connect(host=address, password=password) as connection:
connection.autocommit = True

# Test citext extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(CITEXT_EXTENSION_STATEMENT)

# Test debversion extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(DEBVERSION_EXTENSION_STATEMENT)

# Test hstore extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(HSTORE_EXTENSION_STATEMENT)

# Test pg_trgm extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(PG_TRGM_EXTENSION_STATEMENT)

# Test PL/Python extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(PLPYTHON3U_EXTENSION_STATEMENT)

# Test unaccent extension disabled.
with pytest.raises(psycopg2.Error):
connection.cursor().execute(UNACCENT_EXTENSION_STATEMENT)
for query in sql_tests.values():
with pytest.raises(psycopg2.Error):
connection.cursor().execute(query)
connection.close()

# Enable the plugins.
logger.info("enabling the plugins")
config = {
"plugin_citext_enable": "True",
"plugin_debversion_enable": "True",
"plugin_hstore_enable": "True",
"plugin_pg_trgm_enable": "True",
"plugin_plpython3u_enable": "True",
"plugin_unaccent_enable": "True",
}

config = enable_disable_config(True)
await ops_test.model.applications[DATABASE_APP_NAME].set_config(config)
await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active")

# Check that the available plugins are enabled.
logger.info("checking that the plugins are enabled")
with db_connect(host=address, password=password) as connection:
connection.autocommit = True

# Test citext extension enabled.
connection.cursor().execute(CITEXT_EXTENSION_STATEMENT)

# Test debversion extension enabled.
connection.cursor().execute(DEBVERSION_EXTENSION_STATEMENT)

# Test hstore extension enabled.
connection.cursor().execute(HSTORE_EXTENSION_STATEMENT)

# Test pg_trgm extension enabled.
connection.cursor().execute(PG_TRGM_EXTENSION_STATEMENT)

# Test PL/Python extension enabled.
connection.cursor().execute(PLPYTHON3U_EXTENSION_STATEMENT)

# Test unaccent extension enabled.
connection.cursor().execute(UNACCENT_EXTENSION_STATEMENT)
for query in sql_tests.values():
connection.cursor().execute(query)
connection.close()
77 changes: 73 additions & 4 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,81 @@ def test_enable_disable_extensions(self, _):
plugin_unaccent_enable:
default: false
type: boolean
profile:
default: production
type: string
plugin_debversion_enable:
default: false
type: boolean"""
type: boolean
plugin_bloom_enable:
default: false
type: boolean
plugin_btree_gin_enable:
default: false
type: boolean
plugin_btree_gist_enable:
default: false
type: boolean
plugin_cube_enable:
default: false
type: boolean
plugin_dict_int_enable:
default: false
type: boolean
plugin_dict_xsyn_enable:
default: false
type: boolean
plugin_earthdistance_enable:
default: false
type: boolean
plugin_fuzzystrmatch_enable:
default: false
type: boolean
plugin_intarray_enable:
default: false
type: boolean
plugin_isn_enable:
default: false
type: boolean
plugin_lo_enable:
default: false
type: boolean
plugin_ltree_enable:
default: false
type: boolean
plugin_old_snapshot_enable:
default: false
type: boolean
plugin_pg_freespacemap_enable:
default: false
type: boolean
plugin_pgrowlocks_enable:
default: false
type: boolean
plugin_pgstattuple_enable:
default: false
type: boolean
plugin_pg_visibility_enable:
default: false
type: boolean
plugin_seg_enable:
default: false
type: boolean
plugin_tablefunc_enable:
default: false
type: boolean
plugin_tcn_enable:
default: false
type: boolean
plugin_tsm_system_rows_enable:
default: false
type: boolean
plugin_tsm_system_time_enable:
default: false
type: boolean
plugin_uuid_ossp_enable:
default: false
type: boolean
profile:
default: production
type: string"""
harness = Harness(PostgresqlOperatorCharm, config=config)
self.addCleanup(harness.cleanup)
harness.begin()
Expand Down