Skip to content
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

fix: handle postgresql relation departed #30

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Pebble CVE - Go project issue
# Calling Decoder.Decode on a message which contains deeply nested
# structures can cause a panic due to stack exhaustion.
CVE-2024-34156

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests / Scan Image (ghcr.io-canonical-maubot-008ad8306bcd797dc659e9776a765b04663fc5e5-_0.5.0_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.
# Blackbox Exporter CVEs - Go project issues
CVE-2024-24790

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests / Scan Image (ghcr.io-canonical-maubot-008ad8306bcd797dc659e9776a765b04663fc5e5-_0.5.0_amd64.tar)

CVE-2024-24790 not present anymore, can be safely removed.
CVE-2024-24788

Check notice on line 7 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests / Scan Image (ghcr.io-canonical-maubot-008ad8306bcd797dc659e9776a765b04663fc5e5-_0.5.0_amd64.tar)

CVE-2024-24788 not present anymore, can be safely removed.
# Blackbox
CVE-2024-45337

Check notice on line 9 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests / Scan Image (ghcr.io-canonical-maubot-008ad8306bcd797dc659e9776a765b04663fc5e5-_0.5.0_amd64.tar)

CVE-2024-45337 not present anymore, can be safely removed.
# Pebble
CVE-2024-45338

Check notice on line 11 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests / Scan Image (ghcr.io-canonical-maubot-008ad8306bcd797dc659e9776a765b04663fc5e5-_0.5.0_amd64.tar)

CVE-2024-45338 not present anymore, can be safely removed.
5 changes: 3 additions & 2 deletions src-docs/charm.py.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Maubot charm service.
- **MAUBOT_CONFIGURATION_PATH**
- **MAUBOT_NAME**
- **NGINX_NAME**
- **POSTGRESQL_RELATION_NAME**


---
Expand All @@ -28,7 +29,7 @@ Exception raised when an event fails.
## <kbd>class</kbd> `MaubotCharm`
Maubot charm.

<a href="../lib/charms/loki_k8s/v0/charm_logging.py#L73"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../lib/charms/loki_k8s/v0/charm_logging.py#L74"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>function</kbd> `__init__`

Expand Down Expand Up @@ -89,7 +90,7 @@ Unit that this execution is responsible for.
## <kbd>class</kbd> `MissingRelationDataError`
Custom exception to be raised in case of malformed/missing relation data.

<a href="../src/charm.py#L54"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../src/charm.py#L55"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>function</kbd> `__init__`

Expand Down
11 changes: 10 additions & 1 deletion src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
MAUBOT_CONFIGURATION_PATH = "/data/config.yaml"
MAUBOT_NAME = "maubot"
NGINX_NAME = "nginx"
POSTGRESQL_RELATION_NAME = "postgresql"


class MissingRelationDataError(Exception):
Expand Down Expand Up @@ -91,7 +92,7 @@ def __init__(self, *args: Any):
jobs=self._probes_scraping_job,
)
self.postgresql = DatabaseRequires(
self, relation_name="postgresql", database_name=self.app.name
self, relation_name=POSTGRESQL_RELATION_NAME, database_name=self.app.name
)
self.matrix_auth = MatrixAuthRequires(self)
self.framework.observe(self.on.maubot_pebble_ready, self._on_maubot_pebble_ready)
Expand All @@ -104,6 +105,10 @@ def __init__(self, *args: Any):
# Integrations events handlers
self.framework.observe(self.postgresql.on.database_created, self._on_database_created)
self.framework.observe(self.postgresql.on.endpoints_changed, self._on_endpoints_changed)
self.framework.observe(
self.on[POSTGRESQL_RELATION_NAME].relation_departed,
self._on_postgresql_relation_departed,
)
self.framework.observe(self.ingress.on.ready, self._on_ingress_ready)
self.framework.observe(self.ingress.on.revoked, self._on_ingress_revoked)
self.framework.observe(
Expand Down Expand Up @@ -188,6 +193,10 @@ def _on_endpoints_changed(self, _: DatabaseEndpointsChangedEvent) -> None:
"""Handle endpoints changed event."""
self._reconcile()

def _on_postgresql_relation_departed(self, _: ops.RelationDepartedEvent) -> None:
"""Handle postgresql relation departed event."""
self._reconcile()

def _on_ingress_ready(self, _: IngressPerAppReadyEvent) -> None:
"""Handle ingress ready event."""
self._reconcile()
Expand Down
122 changes: 122 additions & 0 deletions tests/unit/test_charm_scenario.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

"""Unit tests for the Maubot module using Scenario."""

import textwrap
from pathlib import Path

import ops
import pytest
import scenario
from scenario.context import _Event # needed for custom events for now

from charm import MaubotCharm


@pytest.fixture(scope="function", name="base_state")
def base_state_fixture(tmp_path: Path):
"""State with container and config file set."""
config_file_path = tmp_path / "config.yaml"
config_file_path.write_text(
textwrap.dedent(
"""
databases: null
server:
public_url: maubot.local
"""
),
encoding="utf-8",
)
yield {
"leader": True,
"containers": {
scenario.Container(
name="maubot",
can_connect=True,
execs={
scenario.Exec(
command_prefix=["cp"],
return_code=0,
),
scenario.Exec(
command_prefix=["mkdir"],
return_code=0,
),
},
mounts={
"data": scenario.Mount(location="/data/config.yaml", source=config_file_path)
},
)
},
}


def test_config_changed_no_postgresql(base_state: dict):
"""
arrange: prepare maubot container.
act: run config_changed.
assert: status is blocked because there is no postgresql integration.
"""
state = ops.testing.State(**base_state)
context = ops.testing.Context(
charm_type=MaubotCharm,
)
out = context.run(context.on.config_changed(), state)
assert out.unit_status == ops.testing.BlockedStatus("postgresql integration is required")


def test_config_changed_with_postgresql(base_state: dict):
"""
arrange: prepare maubot container.
act: run config_changed.
assert: status is blocked because there is no postgresql integration.
"""
endpoints = "1.2.3.4:5432"
username = "user"
password = "pass" # nosec
database = "maubot"
postgresql_relation = scenario.Relation(
endpoint="postgresql",
interface="postgresql_client",
remote_app_name="postgresql",
remote_app_data={
"endpoints": endpoints,
"username": username,
"password": password,
"database": database,
},
)
base_state["relations"] = [postgresql_relation]
state = ops.testing.State(**base_state)
context = ops.testing.Context(
charm_type=MaubotCharm,
)
out = context.run(context.on.config_changed(), state)
assert out.unit_status == ops.testing.ActiveStatus()
container_root_fs = list(base_state["containers"])[0].get_filesystem(context)
config_file = container_root_fs / "data" / "config.yaml"
assert f"postgresql://{username}:{password}@{endpoints}/{database}" in config_file.read_text()


def test_postgresql_relation_departed(base_state: dict):
"""
arrange: prepare maubot container.
act: run config_changed.
assert: status is blocked because there is no postgresql integration.
"""
postgresql_relation = scenario.Relation(
endpoint="postgresql",
interface="postgresql_client",
remote_app_name="postgresql",
)
base_state["relations"] = [postgresql_relation]
state = ops.testing.State(**base_state)
context = ops.testing.Context(
charm_type=MaubotCharm,
)
postgresql_relation_departed_event = _Event(
"postgresql_relation_departed", relation=postgresql_relation
)
out = context.run(postgresql_relation_departed_event, state)
assert out.unit_status == ops.testing.BlockedStatus("postgresql integration is required")
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ deps =
flake8-test-docs>=1.0
isort
mypy
ops-scenario

Choose a reason for hiding this comment

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

It's better to use ops[testing] and import ops-scenario from there in my opinion

pep8-naming
pydocstyle>=2.10
pylint
Expand Down Expand Up @@ -77,6 +78,7 @@ deps =
pytest
pytest_asyncio
pytest_operator
ops-scenario
-r{toxinidir}/requirements.txt
commands =
coverage run --source={[vars]src_path} \
Expand Down
Loading