Skip to content

Commit

Permalink
feat: Remove defer (#76)
Browse files Browse the repository at this point in the history
Co-authored-by: Gulsum Atici <[email protected]>
  • Loading branch information
Mark Beierl and gatici authored Feb 20, 2024
1 parent 570642b commit 3e9a177
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 151 deletions.
123 changes: 58 additions & 65 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
from charms.data_platform_libs.v0.data_interfaces import DatabaseRequires # type: ignore[import]
from charms.sdcore_nrf_k8s.v0.fiveg_nrf import NRFProvides # type: ignore[import]
from charms.tls_certificates_interface.v3.tls_certificates import ( # type: ignore[import]
CertificateAvailableEvent,
CertificateExpiringEvent,
TLSCertificatesRequiresV3,
generate_csr,
generate_private_key,
)
from jinja2 import Environment, FileSystemLoader # type: ignore[import]
from ops.charm import CharmBase, EventBase, RelationJoinedEvent
from ops.charm import CharmBase, RelationJoinedEvent
from ops.framework import EventBase
from ops.main import main
from ops.model import ActiveStatus, BlockedStatus, ModelError, WaitingStatus
from ops.pebble import Layer
Expand Down Expand Up @@ -110,67 +110,62 @@ def __init__(self, *args):
self.framework.observe(
self.on.fiveg_nrf_relation_joined, self._on_fiveg_nrf_relation_joined
)
self.framework.observe(
self.on.certificates_relation_created, self._on_certificates_relation_created
)
self.framework.observe(
self.on.certificates_relation_joined, self._on_certificates_relation_joined
)
self.framework.observe(self.on.certificates_relation_joined, self._configure_nrf)
self.framework.observe(self._certificates.on.certificate_available, self._configure_nrf)
self.framework.observe(
self.on.certificates_relation_broken, self._on_certificates_relation_broken
)
self.framework.observe(
self._certificates.on.certificate_available, self._on_certificate_available
)
self.framework.observe(
self._certificates.on.certificate_expiring, self._on_certificate_expiring
)

def _configure_nrf(self, event: EventBase) -> None:
"""Adds pebble layer and manages Juju unit status.
Args:
event: Juju event
"""
def ready_to_configure(self) -> bool:
"""Returns whether all preconditions are met to proceed with configuration."""
if not self._container.can_connect():
self.unit.status = WaitingStatus("Waiting for container to be ready")
event.defer()
return
return False
for relation in [DATABASE_RELATION_NAME, "certificates"]:
if not self._relation_created(relation):
self.unit.status = BlockedStatus(f"Waiting for {relation} relation to be created")
return
return False
if not self._database_is_available():
self.unit.status = WaitingStatus("Waiting for the database to be available")
return
return False
if not self._get_database_uri():
self.unit.status = WaitingStatus("Waiting for database URI")
event.defer()
return
if not self._container.exists(path=BASE_CONFIG_PATH):
return False
if not self._container.exists(path=BASE_CONFIG_PATH) or not self._container.exists(
path=CERTS_DIR_PATH
):
self.unit.status = WaitingStatus("Waiting for storage to be attached")
event.defer()
return
return False
if not _get_pod_ip():
self.unit.status = WaitingStatus("Waiting for pod IP address to be available")
event.defer()
return False
return True

def _configure_nrf(self, event: EventBase) -> None:
"""Adds pebble layer and manages Juju unit status.
Args:
event: Juju event
"""
if not self.ready_to_configure():
return
if not self._certificate_is_stored():
if not self._private_key_is_stored():
self._generate_private_key()
if not self._csr_is_stored():
self._request_new_certificate()
provider_certificate = self._get_current_provider_certificate()
if not provider_certificate:
self.unit.status = WaitingStatus("Waiting for certificates to be stored")
event.defer()
return
needs_restart = self._generate_config_file()
self._configure_workload(restart=needs_restart)
certificate_changed = self._update_certificate(provider_certificate=provider_certificate)
config_file_changed = self._generate_config_file()
self._configure_workload(restart=(config_file_changed or certificate_changed))
self._publish_nrf_info_for_all_requirers()
self.unit.status = ActiveStatus()

def _on_certificates_relation_created(self, event: EventBase) -> None:
"""Generates Private key."""
if not self._container.can_connect():
event.defer()
return
self._generate_private_key()

def _on_certificates_relation_broken(self, event: EventBase) -> None:
"""Deletes TLS related artifacts and reconfigures workload."""
if not self._container.can_connect():
Expand All @@ -181,33 +176,6 @@ def _on_certificates_relation_broken(self, event: EventBase) -> None:
self._delete_certificate()
self.unit.status = BlockedStatus("Waiting for certificates relation to be created")

def _on_certificates_relation_joined(self, event: EventBase) -> None:
"""Generates CSR and requests new certificate."""
if not self._container.can_connect():
event.defer()
return
if not self._private_key_is_stored():
event.defer()
return
if self._certificate_is_stored():
return

self._request_new_certificate()

def _on_certificate_available(self, event: CertificateAvailableEvent) -> None:
"""Pushes certificate to workload and configures workload."""
if not self._container.can_connect():
event.defer()
return
if not self._csr_is_stored():
logger.warning("Certificate is available but no CSR is stored")
return
if event.certificate_signing_request != self._get_stored_csr():
logger.debug("Stored CSR doesn't match one in certificate available event")
return
self._store_certificate(event.certificate)
self._configure_nrf(event)

def _on_certificate_expiring(self, event: CertificateExpiringEvent) -> None:
"""Requests new certificate."""
if not self._container.can_connect():
Expand All @@ -226,6 +194,31 @@ def _on_database_relation_broken(self, event: EventBase) -> None:
"""
self.unit.status = BlockedStatus("Waiting for database relation")

def _get_current_provider_certificate(self) -> str | None:
"""Compares the current certificate request to what is in the interface.
Returns The current valid provider certificate if present
"""
csr = self._get_stored_csr()
for provider_certificate in self._certificates.get_assigned_certificates():
if provider_certificate.csr == csr:
return provider_certificate.certificate
return None

def _update_certificate(self, provider_certificate) -> bool:
"""Compares the provided certificate to what is stored.
Returns True if the certificate was updated
"""
existing_certificate = (
self._get_stored_certificate() if self._certificate_is_stored() else ""
)

if existing_certificate != provider_certificate:
self._store_certificate(certificate=provider_certificate)
return True
return False

def _generate_private_key(self) -> None:
"""Generates and stores private key."""
private_key = generate_private_key()
Expand Down
Loading

0 comments on commit 3e9a177

Please sign in to comment.