Skip to content

Commit ec5b5ee

Browse files
Fix cleanup on relation broken (#85)
* fixed issue with cert removal * gitignored external charm lib dependency
1 parent 2a009a9 commit ec5b5ee

File tree

3 files changed

+34
-29
lines changed

3 files changed

+34
-29
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ build/
1010
.tox/
1111
.mypy_cache
1212
.vscode
13-
*.egg-info/
13+
*.egg-info/
14+
/lib/charms/tls_certificates_interface

lib/charms/observability_libs/v1/cert_handler.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565

6666
LIBID = "b5cd5cd580f3428fa5f59a8876dcbe6a"
6767
LIBAPI = 1
68-
LIBPATCH = 5
68+
LIBPATCH = 6
6969

7070

7171
def is_ip_address(value: str) -> bool:
@@ -92,6 +92,10 @@ class CertHandler(Object):
9292

9393
on = CertHandlerEvents() # pyright: ignore
9494

95+
_ca_cert_chain_secret_label = "ca-certificate-chain"
96+
_csr_secret_id = "csr-secret-id"
97+
_privkey_secret_id = "private-key-secret-id"
98+
9599
def __init__(
96100
self,
97101
charm: CharmBase,
@@ -199,7 +203,7 @@ def _generate_privkey(self):
199203
private_key = generate_private_key()
200204
secret = self.charm.unit.add_secret({"private-key": private_key.decode()})
201205
secret.grant(relation)
202-
relation.data[self.charm.unit]["private-key-secret-id"] = secret.id # pyright: ignore
206+
relation.data[self.charm.unit][self._privkey_secret_id] = secret.id # pyright: ignore
203207

204208
def _on_config_changed(self, _):
205209
relation = self.charm.model.get_relation(self.certificates_relation_name)
@@ -265,7 +269,7 @@ def _generate_csr(
265269

266270
if clear_cert:
267271
try:
268-
secret = self.model.get_secret(label="ca-certificate-chain")
272+
secret = self.model.get_secret(label=self._ca_cert_chain_secret_label)
269273
secret.remove_all_revisions()
270274
except SecretNotFoundError:
271275
logger.debug("Secret with label: 'ca-certificate-chain' not found")
@@ -287,19 +291,22 @@ def _on_certificate_available(self, event: CertificateAvailableEvent) -> None:
287291
"chain": event.chain_as_pem(),
288292
"csr": event_csr,
289293
}
294+
if not (relation := self.charm.model.get_relation(self.certificates_relation_name)):
295+
logger.error("Relation %s not found", self.certificates_relation_name)
296+
return
297+
298+
# if we have a secret from a previous certificates relation already, keep it and reuse it.
290299
try:
291-
secret = self.model.get_secret(label="ca-certificate-chain")
300+
secret = self.model.get_secret(label=self._ca_cert_chain_secret_label)
301+
secret.set_content(content)
292302
except SecretNotFoundError:
293-
if not (
294-
relation := self.charm.model.get_relation(self.certificates_relation_name)
295-
):
296-
logger.error("Relation %s not found", self.certificates_relation_name)
297-
return
303+
secret = self.charm.unit.add_secret(
304+
content, label=self._ca_cert_chain_secret_label
305+
)
298306

299-
secret = self.charm.unit.add_secret(content, label="ca-certificate-chain")
300-
secret.grant(relation)
301-
relation.data[self.charm.unit]["secret-id"] = secret.id # pyright: ignore
302-
self.on.cert_changed.emit() # pyright: ignore
307+
secret.grant(relation)
308+
relation.data[self.charm.unit]["secret-id"] = secret.id # pyright: ignore
309+
self.on.cert_changed.emit() # pyright: ignore
303310

304311
def _retrieve_secret_id(self, secret_id_name: str) -> Optional[str]:
305312
if not (relation := self.charm.model.get_relation(self.certificates_relation_name)):
@@ -323,26 +330,26 @@ def _retrieve_from_secret(self, value: str, secret_id_name: str) -> Optional[str
323330
@property
324331
def private_key(self) -> Optional[str]:
325332
"""Private key."""
326-
return self._retrieve_from_secret("private-key", "private-key-secret-id")
333+
return self._retrieve_from_secret("private-key", self._privkey_secret_id)
327334

328335
@property
329336
def private_key_secret_id(self) -> Optional[str]:
330337
"""ID of the Juju Secret for the Private key."""
331-
return self._retrieve_secret_id("private-key-secret-id")
338+
return self._retrieve_secret_id(self._privkey_secret_id)
332339

333340
@property
334341
def _csr(self) -> Optional[str]:
335-
return self._retrieve_from_secret("csr", "csr-secret-id")
342+
return self._retrieve_from_secret("csr", self._csr_secret_id)
336343

337344
@_csr.setter
338345
def _csr(self, value: str):
339346
if not (relation := self.charm.model.get_relation(self.certificates_relation_name)):
340347
return
341348

342-
if not (secret_id := relation.data[self.charm.unit].get("csr-secret-id", None)):
349+
if not (secret_id := relation.data[self.charm.unit].get(self._csr_secret_id, None)):
343350
secret = self.charm.unit.add_secret({"csr": value})
344351
secret.grant(relation)
345-
relation.data[self.charm.unit]["csr-secret-id"] = secret.id # pyright: ignore
352+
relation.data[self.charm.unit][self._csr_secret_id] = secret.id # pyright: ignore
346353
return
347354

348355
secret = self.model.get_secret(id=secret_id)
@@ -403,12 +410,12 @@ def _on_all_certificates_invalidated(self, _: AllCertificatesInvalidatedEvent) -
403410
self.on.cert_changed.emit() # pyright: ignore
404411

405412
def _on_certificates_relation_broken(self, _: RelationBrokenEvent) -> None:
406-
"""Clear the certificates data when removing the relation."""
413+
"""Clear all secrets data when removing the relation."""
407414
try:
408-
secret = self.model.get_secret(label="csr-secret-id")
415+
secret = self.model.get_secret(label=self._ca_cert_chain_secret_label)
409416
secret.remove_all_revisions()
410417
except SecretNotFoundError:
411-
logger.debug("Secret 'csr-scret-id' not found")
418+
logger.debug(f"Secret {self._ca_cert_chain_secret_label!r}' not found")
412419
self.on.cert_changed.emit() # pyright: ignore
413420

414421
def _check_juju_supports_secrets(self) -> None:

tests/scenario/test_cert_handler/test_cert_handler_v1.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
import socket
32
import sys
43
from pathlib import Path
@@ -22,14 +21,12 @@ class MyCharm(CharmBase):
2221
def __init__(self, fw):
2322
super().__init__(fw)
2423

25-
# Set minimal Juju version
26-
os.environ["JUJU_VERSION"] = "3.0.3"
2724
self.ch = CertHandler(self, key="ch", sans=[socket.getfqdn()])
2825

2926

3027
@pytest.fixture
3128
def ctx():
32-
return Context(MyCharm, MyCharm.META)
29+
return Context(MyCharm, MyCharm.META, juju_version="3.0.3")
3330

3431

3532
@pytest.fixture
@@ -41,6 +38,6 @@ def certificates():
4138
def test_cert_joins(ctx, certificates, leader):
4239
with ctx.manager(
4340
certificates.joined_event, State(leader=leader, relations=[certificates])
44-
) as runner:
45-
runner.run()
46-
assert runner.charm.ch.private_key
41+
) as mgr:
42+
mgr.run()
43+
assert mgr.charm.ch.private_key

0 commit comments

Comments
 (0)