Skip to content

Commit aa03501

Browse files
authored
[DPE-3077] Block roles in legacy interface (#302)
* Block if roles are requested * Unconditionally skip the nextcloud test * Mangled comment
1 parent b2889e0 commit aa03501

File tree

7 files changed

+87
-10
lines changed

7 files changed

+87
-10
lines changed

src/relations/db.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
"extensions requested through relation, enable them through config options"
3232
)
3333

34+
ROLES_BLOCKING_MESSAGE = (
35+
"roles requested through relation, use postgresql_client interface instead"
36+
)
37+
3438

3539
class DbProvides(Object):
3640
"""Defines functionality for the 'provides' side of the 'db' relation.
@@ -70,7 +74,7 @@ def __init__(self, charm: CharmBase, admin: bool = False):
7074
self.charm = charm
7175

7276
def _check_for_blocking_relations(self, relation_id: int) -> bool:
73-
"""Checks if there are relations with extensions.
77+
"""Checks if there are relations with extensions or roles.
7478
7579
Args:
7680
relation_id: current relation to be skipped
@@ -80,7 +84,7 @@ def _check_for_blocking_relations(self, relation_id: int) -> bool:
8084
if relation.id == relation_id:
8185
continue
8286
for data in relation.data.values():
83-
if "extensions" in data:
87+
if "extensions" in data or "roles" in data:
8488
return True
8589
return False
8690

@@ -127,6 +131,10 @@ def _get_extensions(self, relation: Relation) -> Tuple[List, Set]:
127131
disabled_extensions.add(extension_name)
128132
return required_extensions, disabled_extensions
129133

134+
def _get_roles(self, relation: Relation) -> bool:
135+
"""Checks if relation required roles."""
136+
return "roles" in relation.data.get(relation.app, {})
137+
130138
def set_up_relation(self, relation: Relation) -> bool:
131139
"""Set up the relation to be used by the application charm."""
132140
# Do not allow apps requesting extensions to be installed
@@ -139,6 +147,9 @@ def set_up_relation(self, relation: Relation) -> bool:
139147
)
140148
self.charm.unit.status = BlockedStatus(EXTENSIONS_BLOCKING_MESSAGE)
141149
return False
150+
if self._get_roles(relation):
151+
self.charm.unit.status = BlockedStatus(ROLES_BLOCKING_MESSAGE)
152+
return False
142153

143154
database = relation.data.get(relation.app, {}).get("database")
144155
if not database:
@@ -261,7 +272,10 @@ def _on_relation_broken(self, event: RelationBrokenEvent) -> None:
261272

262273
def _update_unit_status(self, relation: Relation) -> None:
263274
"""Clean up Blocked status if it's due to extensions request."""
264-
if self.charm.is_blocked and self.charm.unit.status.message == EXTENSIONS_BLOCKING_MESSAGE:
275+
if self.charm.is_blocked and self.charm.unit.status.message in [
276+
EXTENSIONS_BLOCKING_MESSAGE,
277+
ROLES_BLOCKING_MESSAGE,
278+
]:
265279
if not self._check_for_blocking_relations(relation.id):
266280
self.charm.unit.status = ActiveStatus()
267281

tests/integration/ha_tests/helpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
wait_fixed,
2121
)
2222

23-
from ..helpers import db_connect, get_unit_address, run_command_on_unit
23+
from ..helpers import APPLICATION_NAME, db_connect, get_unit_address, run_command_on_unit
2424

25-
APPLICATION_NAME = "postgresql-test-app"
2625
METADATA = yaml.safe_load(Path("./metadata.yaml").read_text())
2726
PORT = 5432
2827
APP_NAME = METADATA["name"]

tests/integration/ha_tests/test_replication.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
from pytest_operator.plugin import OpsTest
77
from tenacity import Retrying, stop_after_delay, wait_fixed
88

9-
from ..helpers import CHARM_SERIES, db_connect, scale_application
9+
from ..helpers import APPLICATION_NAME, CHARM_SERIES, db_connect, scale_application
1010
from .helpers import (
11-
APPLICATION_NAME,
1211
app_name,
1312
are_writes_increasing,
1413
check_writes,

tests/integration/ha_tests/test_upgrade.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
from pytest_operator.plugin import OpsTest
1313

1414
from ..helpers import (
15+
APPLICATION_NAME,
1516
DATABASE_APP_NAME,
1617
count_switchovers,
1718
get_leader_unit,
1819
get_primary,
1920
)
2021
from ..new_relations.helpers import get_application_relation_data
2122
from .helpers import (
22-
APPLICATION_NAME,
2323
are_writes_increasing,
2424
check_writes,
2525
start_continuous_writes,

tests/integration/ha_tests/test_upgrade_from_stable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
from pytest_operator.plugin import OpsTest
88

99
from ..helpers import (
10+
APPLICATION_NAME,
1011
DATABASE_APP_NAME,
1112
count_switchovers,
1213
get_leader_unit,
1314
get_primary,
1415
remove_chown_workaround,
1516
)
1617
from .helpers import (
17-
APPLICATION_NAME,
1818
are_writes_increasing,
1919
check_writes,
2020
start_continuous_writes,

tests/integration/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
METADATA = yaml.safe_load(Path("./metadata.yaml").read_text())
3535
DATABASE_APP_NAME = METADATA["name"]
3636
STORAGE_PATH = METADATA["storage"]["pgdata"]["location"]
37+
APPLICATION_NAME = "postgresql-test-app"
3738

3839

3940
async def build_connection_string(

tests/integration/test_db.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from . import markers
1515
from .helpers import (
16+
APPLICATION_NAME,
1617
CHARM_SERIES,
1718
DATABASE_APP_NAME,
1819
build_connection_string,
@@ -21,6 +22,7 @@
2122
deploy_and_relate_application_with_postgresql,
2223
deploy_and_relate_bundle_with_postgresql,
2324
find_unit,
25+
get_leader_unit,
2426
run_command_on_unit,
2527
)
2628

@@ -32,6 +34,10 @@
3234
DATABASE_UNITS = 2
3335
RELATION_NAME = "db"
3436

37+
ROLES_BLOCKING_MESSAGE = (
38+
"roles requested through relation, use postgresql_client interface instead"
39+
)
40+
3541

3642
@pytest.mark.group(1)
3743
async def test_mailman3_core_db(ops_test: OpsTest, charm: str) -> None:
@@ -173,7 +179,7 @@ async def test_relation_data_is_updated_correctly_when_scaling(ops_test: OpsTest
173179

174180

175181
@pytest.mark.group(1)
176-
@pytest.mark.unstable
182+
@pytest.mark.skip(reason="Should be ported and moved to the new relation tests")
177183
async def test_nextcloud_db_blocked(ops_test: OpsTest, charm: str) -> None:
178184
async with ops_test.fast_forward():
179185
# Deploy Nextcloud.
@@ -294,6 +300,64 @@ async def test_sentry_db_blocked(ops_test: OpsTest, charm: str) -> None:
294300
)
295301

296302

303+
@pytest.mark.group(1)
304+
async def test_roles_blocking(ops_test: OpsTest, charm: str) -> None:
305+
await ops_test.model.deploy(
306+
APPLICATION_NAME,
307+
application_name=APPLICATION_NAME,
308+
config={"legacy_roles": True},
309+
series=CHARM_SERIES,
310+
channel="edge",
311+
)
312+
await ops_test.model.deploy(
313+
APPLICATION_NAME,
314+
application_name=f"{APPLICATION_NAME}2",
315+
config={"legacy_roles": True},
316+
series=CHARM_SERIES,
317+
channel="edge",
318+
)
319+
320+
await ops_test.model.wait_for_idle(
321+
apps=[DATABASE_APP_NAME, APPLICATION_NAME, f"{APPLICATION_NAME}2"],
322+
status="active",
323+
timeout=1000,
324+
)
325+
326+
await asyncio.gather(
327+
ops_test.model.relate(f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}:db"),
328+
ops_test.model.relate(f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}2:db"),
329+
)
330+
331+
leader_unit = await get_leader_unit(ops_test, DATABASE_APP_NAME)
332+
await ops_test.model.block_until(
333+
lambda: leader_unit.workload_status_message == ROLES_BLOCKING_MESSAGE, timeout=1000
334+
)
335+
336+
assert leader_unit.workload_status_message == ROLES_BLOCKING_MESSAGE
337+
338+
logger.info("Verify that the charm remains blocked if there are other blocking relations")
339+
await ops_test.model.applications[DATABASE_APP_NAME].destroy_relation(
340+
f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}:db"
341+
)
342+
343+
await ops_test.model.block_until(
344+
lambda: leader_unit.workload_status_message == ROLES_BLOCKING_MESSAGE, timeout=1000
345+
)
346+
347+
assert leader_unit.workload_status_message == ROLES_BLOCKING_MESSAGE
348+
349+
logger.info("Verify that active status is restored when all blocking relations are gone")
350+
await ops_test.model.applications[DATABASE_APP_NAME].destroy_relation(
351+
f"{DATABASE_APP_NAME}:db", f"{APPLICATION_NAME}2:db"
352+
)
353+
354+
await ops_test.model.wait_for_idle(
355+
apps=[DATABASE_APP_NAME],
356+
status="active",
357+
timeout=1000,
358+
)
359+
360+
297361
@pytest.mark.group(1)
298362
@pytest.mark.unstable
299363
async def test_weebl_db(ops_test: OpsTest, charm: str) -> None:

0 commit comments

Comments
 (0)