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

do not raise on missing peer relation when being destroyed #293

Merged
merged 10 commits into from
Feb 6, 2024
22 changes: 18 additions & 4 deletions lib/charms/grafana_k8s/v0/grafana_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def __init__(self, *args):

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

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -648,7 +648,7 @@ def _remove_source_from_datastore(self, event: RelationDepartedEvent) -> bool:

def _remove_source(self, source_name: str) -> None:
"""Remove a datasource by name."""
sources_to_delete = self.get_peer_data("sources_to_delete")
sources_to_delete = self.get_peer_data("sources_to_delete") or []
if source_name not in sources_to_delete:
sources_to_delete.append(source_name)
self.set_peer_data("sources_to_delete", sources_to_delete)
Expand Down Expand Up @@ -713,7 +713,7 @@ def sources(self) -> List[dict]:
@property
def sources_to_delete(self) -> List[str]:
"""Returns an array of source names which have been removed."""
return self.get_peer_data("sources_to_delete")
return self.get_peer_data("sources_to_delete") or []

def _set_default_data(self) -> None:
"""Set defaults if they are not in peer relation data."""
Expand All @@ -724,9 +724,23 @@ def _set_default_data(self) -> None:

def set_peer_data(self, key: str, data: Any) -> None:
"""Put information into the peer data bucket instead of `StoredState`."""
self._charm.peers.data[self._charm.app][key] = json.dumps(data) # type: ignore[attr-defined]
peers = self._charm.peers # type: ignore[attr-defined]
if not peers:
# https://bugs.launchpad.net/juju/+bug/1998282
logger.info("set_peer_data: no peer relation. Is the charm being installed/removed?")
return

peers.data[self._charm.app][key] = json.dumps(data) # type: ignore[attr-defined]

def get_peer_data(self, key: str) -> Any:
"""Retrieve information from the peer data bucket instead of `StoredState`."""
peers = self._charm.peers # type: ignore[attr-defined]
if not peers:
# https://bugs.launchpad.net/juju/+bug/1998282
logger.warning(
PietroPasotti marked this conversation as resolved.
Show resolved Hide resolved
"get_peer_data: no peer relation. Is the charm being installed/removed?"
)
return {}
PietroPasotti marked this conversation as resolved.
Show resolved Hide resolved

data = self._charm.peers.data[self._charm.app].get(key, "") # type: ignore[attr-defined]
return json.loads(data) if data else {}
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ jsonschema
cryptography

# lib/charms/tempo_k8s/v1/charm_tracing.py
opentelemetry-exporter-otlp-proto-http
opentelemetry-exporter-otlp-proto-http
pydantic
35 changes: 35 additions & 0 deletions tests/scenario/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from unittest.mock import patch, MagicMock

import pytest
from scenario import Context

from charm import GrafanaCharm


def tautology(*_, **__) -> bool:
PietroPasotti marked this conversation as resolved.
Show resolved Hide resolved
return True


@pytest.fixture
def ctx():
patches = (
patch("lightkube.core.client.GenericSyncClient"),
patch("socket.getfqdn", new=lambda *args: "grafana-k8s-0.testmodel.svc.cluster.local"),
patch("socket.gethostbyname", new=lambda *args: "1.2.3.4"),
patch.multiple(
"charm.KubernetesComputeResourcesPatch",
_namespace="test-namespace",
_patch=tautology,
is_ready=tautology,
),
patch.object(GrafanaCharm, "grafana_version", "0.1.0"),
patch("ops.testing._TestingModelBackend.network_get"),
patch("ops.testing._TestingPebbleClient.exec", MagicMock()),
)
for p in patches:
p.__enter__()

yield Context(GrafanaCharm)

for p in patches:
p.__exit__(None, None, None)
21 changes: 21 additions & 0 deletions tests/scenario/test_charm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest
from scenario import State, PeerRelation


@pytest.mark.parametrize("leader", (True, False))
def test_peer_data_does_not_raise_if_no_peers(ctx, leader):
state = State(leader=leader)
with ctx.manager("update-status", state) as mgr:
charm = mgr.charm
assert not charm.peers
charm.set_peer_data("1", 2)
assert charm.get_peer_data("1") == {}


def test_peer_data_if_peers(ctx):
state = State(leader=True, relations=[PeerRelation("grafana")])
with ctx.manager("update-status", state) as mgr:
charm = mgr.charm
assert charm.peers
charm.set_peer_data("1", 2)
assert charm.get_peer_data("1") == 2
12 changes: 12 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ allowlist_externals =

[testenv:scenario]
description = Run scenario tests
deps =
pytest
responses
cosl
ops-scenario==6
-r{toxinidir}/requirements.txt
commands =
/usr/bin/env sh -c 'stat sqlite-static > /dev/null 2>&1 || curl -L https://github.com/CompuRoot/static-sqlite3/releases/latest/download/sqlite3 -o sqlite-static && chmod +x sqlite-static'
/usr/bin/env sh -c 'stat cos-tool-amd64 > /dev/null 2>&1 || curl -L -O https://github.com/canonical/cos-tool/releases/latest/download/cos-tool-amd64'
pytest -v --tb native -s {posargs} {[vars]tst_path}/scenario
allowlist_externals =
/usr/bin/env


[testenv:integration]
Expand Down
Loading