Skip to content

Commit

Permalink
[MISC] Update rock due to outdated packages (#387)
Browse files Browse the repository at this point in the history
* Update rock

* Update libs

* Fix unit tests
  • Loading branch information
dragomirp authored Feb 5, 2024
1 parent 4779785 commit 98dcdbb
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 54 deletions.
62 changes: 30 additions & 32 deletions lib/charms/data_platform_libs/v0/data_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):

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

PYDEPS = ["ops>=2.0.0"]

Expand Down Expand Up @@ -422,15 +422,15 @@ def diff(event: RelationChangedEvent, bucket: Union[Unit, Application]) -> Diff:
)

# These are the keys that were added to the databag and triggered this event.
added = new_data.keys() - old_data.keys() # pyright: ignore [reportGeneralTypeIssues]
added = new_data.keys() - old_data.keys() # pyright: ignore [reportAssignmentType]
# These are the keys that were removed from the databag and triggered this event.
deleted = old_data.keys() - new_data.keys() # pyright: ignore [reportGeneralTypeIssues]
deleted = old_data.keys() - new_data.keys() # pyright: ignore [reportAssignmentType]
# These are the keys that already existed in the databag,
# but had their values changed.
changed = {
key
for key in old_data.keys() & new_data.keys() # pyright: ignore [reportGeneralTypeIssues]
if old_data[key] != new_data[key] # pyright: ignore [reportGeneralTypeIssues]
for key in old_data.keys() & new_data.keys() # pyright: ignore [reportAssignmentType]
if old_data[key] != new_data[key] # pyright: ignore [reportAssignmentType]
}
# Convert the new_data to a serializable format and save it for a next diff check.
set_encoded_field(event.relation, bucket, "data", new_data)
Expand Down Expand Up @@ -1619,7 +1619,8 @@ def _delete_relation_data(self, relation: Relation, fields: List[str]) -> None:
current_data.get(relation.id, [])
):
logger.error(
"Non-existing secret %s was attempted to be removed.", non_existent
"Non-existing secret %s was attempted to be removed.",
", ".join(non_existent),
)

_, normal_fields = self._process_secret_fields(
Expand Down Expand Up @@ -1686,12 +1687,8 @@ def extra_user_roles(self) -> Optional[str]:
return self.relation.data[self.relation.app].get("extra-user-roles")


class AuthenticationEvent(RelationEvent):
"""Base class for authentication fields for events.
The amount of logic added here is not ideal -- but this was the only way to preserve
the interface when moving to Juju Secrets
"""
class RelationEventWithSecret(RelationEvent):
"""Base class for Relation Events that need to handle secrets."""

@property
def _secrets(self) -> dict:
Expand All @@ -1703,18 +1700,6 @@ def _secrets(self) -> dict:
self._cached_secrets = {}
return self._cached_secrets

@property
def _jujuversion(self) -> JujuVersion:
"""Caching jujuversion to avoid a Juju call on each field evaluation.
DON'T USE the encapsulated helper variable outside of this function
"""
if not hasattr(self, "_cached_jujuversion"):
self._cached_jujuversion = None
if not self._cached_jujuversion:
self._cached_jujuversion = JujuVersion.from_environ()
return self._cached_jujuversion

def _get_secret(self, group) -> Optional[Dict[str, str]]:
"""Retrieveing secrets."""
if not self.app:
Expand All @@ -1730,7 +1715,15 @@ def _get_secret(self, group) -> Optional[Dict[str, str]]:
@property
def secrets_enabled(self):
"""Is this Juju version allowing for Secrets usage?"""
return self._jujuversion.has_secrets
return JujuVersion.from_environ().has_secrets


class AuthenticationEvent(RelationEventWithSecret):
"""Base class for authentication fields for events.
The amount of logic added here is not ideal -- but this was the only way to preserve
the interface when moving to Juju Secrets
"""

@property
def username(self) -> Optional[str]:
Expand Down Expand Up @@ -1813,7 +1806,7 @@ class DatabaseProvidesEvents(CharmEvents):
database_requested = EventSource(DatabaseRequestedEvent)


class DatabaseRequiresEvent(RelationEvent):
class DatabaseRequiresEvent(RelationEventWithSecret):
"""Base class for database events."""

@property
Expand Down Expand Up @@ -1868,6 +1861,11 @@ def uris(self) -> Optional[str]:
if not self.relation.app:
return None

if self.secrets_enabled:
secret = self._get_secret("user")
if secret:
return secret.get("uris")

return self.relation.data[self.relation.app].get("uris")

@property
Expand Down Expand Up @@ -1911,7 +1909,7 @@ class DatabaseRequiresEvents(CharmEvents):
class DatabaseProvides(DataProvides):
"""Provider-side of the database relations."""

on = DatabaseProvidesEvents() # pyright: ignore [reportGeneralTypeIssues]
on = DatabaseProvidesEvents() # pyright: ignore [reportAssignmentType]

def __init__(self, charm: CharmBase, relation_name: str) -> None:
super().__init__(charm, relation_name)
Expand Down Expand Up @@ -2006,7 +2004,7 @@ def set_version(self, relation_id: int, version: str) -> None:
class DatabaseRequires(DataRequires):
"""Requires-side of the database relation."""

on = DatabaseRequiresEvents() # pyright: ignore [reportGeneralTypeIssues]
on = DatabaseRequiresEvents() # pyright: ignore [reportAssignmentType]

def __init__(
self,
Expand Down Expand Up @@ -2335,7 +2333,7 @@ class KafkaRequiresEvents(CharmEvents):
class KafkaProvides(DataProvides):
"""Provider-side of the Kafka relation."""

on = KafkaProvidesEvents() # pyright: ignore [reportGeneralTypeIssues]
on = KafkaProvidesEvents() # pyright: ignore [reportAssignmentType]

def __init__(self, charm: CharmBase, relation_name: str) -> None:
super().__init__(charm, relation_name)
Expand Down Expand Up @@ -2396,7 +2394,7 @@ def set_zookeeper_uris(self, relation_id: int, zookeeper_uris: str) -> None:
class KafkaRequires(DataRequires):
"""Requires-side of the Kafka relation."""

on = KafkaRequiresEvents() # pyright: ignore [reportGeneralTypeIssues]
on = KafkaRequiresEvents() # pyright: ignore [reportAssignmentType]

def __init__(
self,
Expand Down Expand Up @@ -2533,7 +2531,7 @@ class OpenSearchRequiresEvents(CharmEvents):
class OpenSearchProvides(DataProvides):
"""Provider-side of the OpenSearch relation."""

on = OpenSearchProvidesEvents() # pyright: ignore[reportGeneralTypeIssues]
on = OpenSearchProvidesEvents() # pyright: ignore[reportAssignmentType]

def __init__(self, charm: CharmBase, relation_name: str) -> None:
super().__init__(charm, relation_name)
Expand Down Expand Up @@ -2586,7 +2584,7 @@ def set_version(self, relation_id: int, version: str) -> None:
class OpenSearchRequires(DataRequires):
"""Requires-side of the OpenSearch relation."""

on = OpenSearchRequiresEvents() # pyright: ignore[reportGeneralTypeIssues]
on = OpenSearchRequiresEvents() # pyright: ignore[reportAssignmentType]

def __init__(
self,
Expand Down
18 changes: 16 additions & 2 deletions lib/charms/loki_k8s/v0/loki_push_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ def _alert_rules_error(self, event):

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

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -2115,7 +2115,21 @@ def _download_and_push_promtail_to_workload(self, promtail_info: dict) -> None:
- "zipsha": sha256 sum of zip file of promtail binary
- "binsha": sha256 sum of unpacked promtail binary
"""
with request.urlopen(promtail_info["url"]) as r:
# Check for Juju proxy variables and fall back to standard ones if not set
proxies: Optional[Dict[str, str]] = {}
if proxies and os.environ.get("JUJU_CHARM_HTTP_PROXY"):
proxies.update({"http": os.environ["JUJU_CHARM_HTTP_PROXY"]})
if proxies and os.environ.get("JUJU_CHARM_HTTPS_PROXY"):
proxies.update({"https": os.environ["JUJU_CHARM_HTTPS_PROXY"]})
if proxies and os.environ.get("JUJU_CHARM_NO_PROXY"):
proxies.update({"no_proxy": os.environ["JUJU_CHARM_NO_PROXY"]})
else:
proxies = None

proxy_handler = request.ProxyHandler(proxies)
opener = request.build_opener(proxy_handler)

with opener.open(promtail_info["url"]) as r:
file_bytes = r.read()
file_path = os.path.join(BINARY_DIR, promtail_info["filename"] + ".gz")
with open(file_path, "wb") as f:
Expand Down
39 changes: 32 additions & 7 deletions lib/charms/rolling_ops/v0/rollingops.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def _on_trigger_restart(self, event):
"""
import logging
from enum import Enum
from typing import AnyStr, Callable
from typing import AnyStr, Callable, Optional

from ops.charm import ActionEvent, CharmBase, RelationChangedEvent
from ops.framework import EventBase, Object
Expand All @@ -88,7 +88,7 @@ def _on_trigger_restart(self, event):

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


class LockNoRelationError(Exception):
Expand Down Expand Up @@ -261,7 +261,15 @@ class RunWithLock(EventBase):
class AcquireLock(EventBase):
"""Signals that this unit wants to acquire a lock."""

pass
def __init__(self, handle, callback_override: Optional[str] = None):
super().__init__(handle)
self.callback_override = callback_override or ""

def snapshot(self):
return {"callback_override": self.callback_override}

def restore(self, snapshot):
self.callback_override = snapshot["callback_override"]


class ProcessLocks(EventBase):
Expand Down Expand Up @@ -366,25 +374,42 @@ def _on_process_locks(self: CharmBase, event: ProcessLocks):
self.charm.on[self.name].run_with_lock.emit()
return

self.model.app.status = ActiveStatus()
if self.model.app.status.message == f"Beginning rolling {self.name}":
self.model.app.status = ActiveStatus()

def _on_acquire_lock(self: CharmBase, event: ActionEvent):
"""Request a lock."""
try:
Lock(self).acquire() # Updates relation data
# emit relation changed event in the edge case where aquire does not
relation = self.model.get_relation(self.name)
self.charm.on[self.name].relation_changed.emit(relation)

# persist callback override for eventual run
relation.data[self.charm.unit].update({"callback_override": event.callback_override})
self.charm.on[self.name].relation_changed.emit(relation, app=self.charm.app)

except LockNoRelationError:
logger.debug("No {} peer relation yet. Delaying rolling op.".format(self.name))
event.defer()

def _on_run_with_lock(self: CharmBase, event: RunWithLock):
lock = Lock(self)
self.model.unit.status = MaintenanceStatus("Executing {} operation".format(self.name))
self._callback(event)
relation = self.model.get_relation(self.name)

# default to instance callback if not set
callback_name = relation.data[self.charm.unit].get(
"callback_override", self._callback.__name__
)
callback = getattr(self.charm, callback_name)
callback(event)

lock.release() # Updates relation data
if lock.unit == self.model.unit:
self.charm.on[self.name].process_locks.emit()

self.model.unit.status = ActiveStatus()
# cleanup old callback overrides
relation.data[self.charm.unit].update({"callback_override": ""})

if self.model.unit.status.message == f"Executing {self.name} operation":
self.model.unit.status = ActiveStatus()
21 changes: 11 additions & 10 deletions lib/charms/tls_certificates_interface/v2/tls_certificates.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ def _on_all_certificates_invalidated(self, event: AllCertificatesInvalidatedEven
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography.x509.extensions import Extension, ExtensionNotFound
from jsonschema import exceptions, validate # type: ignore[import-untyped]
from ops.charm import (
CharmBase,
Expand All @@ -308,7 +307,7 @@ def _on_all_certificates_invalidated(self, event: AllCertificatesInvalidatedEven

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

PYDEPS = ["cryptography", "jsonschema"]

Expand Down Expand Up @@ -939,9 +938,11 @@ def generate_private_key(
key_bytes = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.BestAvailableEncryption(password)
if password
else serialization.NoEncryption(),
encryption_algorithm=(
serialization.BestAvailableEncryption(password)
if password
else serialization.NoEncryption()
),
)
return key_bytes

Expand Down Expand Up @@ -1676,7 +1677,7 @@ def get_assigned_certificates(self) -> List[Dict[str, str]]:
"""
final_list = []
for csr in self.get_certificate_signing_requests(fulfilled_only=True):
assert type(csr["certificate_signing_request"]) == str
assert isinstance(csr["certificate_signing_request"], str)
if cert := self._find_certificate_in_relation_data(csr["certificate_signing_request"]):
final_list.append(cert)
return final_list
Expand All @@ -1699,7 +1700,7 @@ def get_expiring_certificates(self) -> List[Dict[str, str]]:
"""
final_list = []
for csr in self.get_certificate_signing_requests(fulfilled_only=True):
assert type(csr["certificate_signing_request"]) == str
assert isinstance(csr["certificate_signing_request"], str)
if cert := self._find_certificate_in_relation_data(csr["certificate_signing_request"]):
expiry_time = _get_certificate_expiry_time(cert["certificate"])
if not expiry_time:
Expand All @@ -1719,11 +1720,12 @@ def get_certificate_signing_requests(
"""Gets the list of CSR's that were sent to the provider.
You can choose to get only the CSR's that have a certificate assigned or only the CSR's
that don't.
that don't.
Args:
fulfilled_only (bool): This option will discard CSRs that don't have certificates yet.
unfulfilled_only (bool): This option will discard CSRs that have certificates signed.
Returns:
List of CSR dictionaries. For example:
[
Expand All @@ -1733,10 +1735,9 @@ def get_certificate_signing_requests(
}
]
"""

final_list = []
for csr in self._requirer_csrs:
assert type(csr["certificate_signing_request"]) == str
assert isinstance(csr["certificate_signing_request"], str)
cert = self._find_certificate_in_relation_data(csr["certificate_signing_request"])
if (unfulfilled_only and cert) or (fulfilled_only and not cert):
continue
Expand Down
2 changes: 1 addition & 1 deletion metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ resources:
postgresql-image:
type: oci-image
description: OCI image for PostgreSQL
upstream-source: ghcr.io/canonical/charmed-postgresql@sha256:ff74e3e8fc0e08e7b952cb69477f1a39e94e7caa156f06bbb844e752bec42f0b
upstream-source: ghcr.io/canonical/charmed-postgresql@sha256:0cfc8cc4c096abdd713480d7cfa300e4edb15b59fc7db429a073a2c8179f5248

peers:
database-peers:
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,13 +909,13 @@ def test_delete_existing_password_secrets(self, _, __):
with self._caplog.at_level(logging.ERROR):
self.harness.charm.remove_secret("app", "operator-password")
assert (
"Non-existing secret {'operator-password'} was attempted to be removed."
"Non-existing secret operator-password was attempted to be removed."
in self._caplog.text
)

self.harness.charm.remove_secret("unit", "operator-password")
assert (
"Non-existing secret {'operator-password'} was attempted to be removed."
"Non-existing secret operator-password was attempted to be removed."
in self._caplog.text
)

Expand Down

0 comments on commit 98dcdbb

Please sign in to comment.