diff --git a/lib/charms/data_platform_libs/v0/data_interfaces.py b/lib/charms/data_platform_libs/v0/data_interfaces.py index c940cc00..0cafcef5 100644 --- a/lib/charms/data_platform_libs/v0/data_interfaces.py +++ b/lib/charms/data_platform_libs/v0/data_interfaces.py @@ -558,6 +558,16 @@ def get_info(self) -> Optional[SecretInfo]: if self.meta: return self.meta.get_info() + def remove(self) -> None: + """Remove secret.""" + try: + self.meta.remove_all_revisions() + except SecretNotFoundError: + pass + self._secret_content = None + self._secret_meta = None + self._secret_uri = None + class SecretCache: """A data structure storing CachedSecret objects.""" @@ -603,8 +613,10 @@ class DataRelation(Object, ABC): "tls-ca": SecretGroup.TLS, } - def __init__(self, charm: CharmBase, relation_name: str) -> None: - super().__init__(charm, relation_name) + def __init__(self, charm: CharmBase, relation_name: str, unique_key: Optional[str] = None) -> None: + if not unique_key: + unique_key = relation_name + super().__init__(charm, unique_key) self.charm = charm self.local_app = self.charm.model.app self.local_unit = self.charm.unit @@ -799,7 +811,7 @@ def _process_secret_fields( # self.local_app is sufficient to check (ignored if Requires, never has secrets -- works if Provides) fallback_to_databag = ( req_secret_fields - and self.local_unit.is_leader() + and (self.local_unit == self.charm.unit and self.local_unit.is_leader()) and set(req_secret_fields) & set(relation.data[self.component]) ) @@ -860,16 +872,17 @@ def _fetch_relation_data_with_secrets( normal_fields = [] if not fields: - if component not in relation.data or not relation.data[component]: + if component not in relation.data: return {} all_fields = list(relation.data[component].keys()) normal_fields = [field for field in all_fields if not self._is_secret_field(field)] - - # There must have been secrets there - if all_fields != normal_fields and req_secret_fields: - # So we assemble the full fields list (without 'secret-' fields) - fields = normal_fields + req_secret_fields + # + # # There must have been secrets there + # if all_fields != normal_fields and req_secret_fields: + # # So we assemble the full fields list (without 'secret-' fields) + # fields = normal_fields + req_secret_fields + fields = normal_fields + req_secret_fields if fields: result, normal_fields = self._process_secret_fields( @@ -1029,8 +1042,8 @@ def delete_relation_data(self, relation_id: int, fields: List[str]) -> None: class DataProvides(DataRelation): """Base provides-side of the data products relation.""" - def __init__(self, charm: CharmBase, relation_name: str) -> None: - super().__init__(charm, relation_name) + def __init__(self, charm: CharmBase, relation_name: str, unique_key: Optional[str] = None) -> None: + super().__init__(charm, relation_name, unique_key) def _diff(self, event: RelationChangedEvent) -> Diff: """Retrieves the diff of the data in the relation changed databag. @@ -1136,8 +1149,6 @@ def _delete_relation_secret( ) return False - secret.set_content(new_content) - # Remove secret from the relation if it's fully gone if not new_content: field = self._generate_secret_field_name(group) @@ -1145,6 +1156,9 @@ def _delete_relation_secret( relation.data[self.component].pop(field) except KeyError: pass + secret.remove() + else: + secret.set_content(new_content) # Return the content that was removed return True @@ -1276,9 +1290,10 @@ def __init__( relation_name: str, extra_user_roles: Optional[str] = None, additional_secret_fields: Optional[List[str]] = [], + unique_key: Optional[str] = None ): """Manager of base client relations.""" - super().__init__(charm, relation_name) + super().__init__(charm, relation_name, unique_key) self.extra_user_roles = extra_user_roles self._secret_fields = list(self.SECRET_FIELDS) if additional_secret_fields: @@ -1481,10 +1496,11 @@ def __init__( additional_secret_fields: Optional[List[str]] = [], secret_field_name: Optional[str] = None, deleted_label: Optional[str] = None, + unique_key: Optional[str] = None ): """Manager of base client relations.""" DataRequires.__init__( - self, charm, relation_name, extra_user_roles, additional_secret_fields + self, charm, relation_name, extra_user_roles, additional_secret_fields, unique_key=unique_key ) self.secret_field_name = secret_field_name if secret_field_name else self.SECRET_FIELD_NAME self.deleted_label = deleted_label @@ -1672,6 +1688,16 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) +class DataPeerOtherUnit(DataPeerUnit): + """Unit databag representation for another unit than the executor.""" + + def __init__(self, unit: Unit, relation_name: str, *args, **kwargs): + unique_key = f'{relation_name}-{unit.name}' + super().__init__(unique_key=unique_key, relation_name=relation_name, *args, **kwargs) + self.local_unit = unit + self.component = unit + + # General events