@@ -320,7 +320,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):
320
320
321
321
# Increment this PATCH version before using `charmcraft publish-lib` or reset
322
322
# to 0 if you are raising the major API version
323
- LIBPATCH = 21
323
+ LIBPATCH = 22
324
324
325
325
PYDEPS = ["ops>=2.0.0" ]
326
326
@@ -763,14 +763,23 @@ def _process_secret_fields(
763
763
req_secret_fields : Optional [List [str ]],
764
764
impacted_rel_fields : List [str ],
765
765
operation : Callable ,
766
- second_chance_as_normal_field : bool = True ,
767
766
* args ,
768
767
** kwargs ,
769
768
) -> Tuple [Dict [str , str ], Set [str ]]:
770
769
"""Isolate target secret fields of manipulation, and execute requested operation by Secret Group."""
771
770
result = {}
771
+
772
+ # If the relation started on a databag, we just stay on the databag
773
+ # (Rolling upgrades may result in a relation starting on databag, getting secrets enabled on-the-fly)
774
+ # self.local_app is sufficient to check (ignored if Requires, never has secrets -- works if Provides)
775
+ fallback_to_databag = (
776
+ req_secret_fields
777
+ and self .local_unit .is_leader ()
778
+ and set (req_secret_fields ) & set (relation .data [self .local_app ])
779
+ )
780
+
772
781
normal_fields = set (impacted_rel_fields )
773
- if req_secret_fields and self .secrets_enabled :
782
+ if req_secret_fields and self .secrets_enabled and not fallback_to_databag :
774
783
normal_fields = normal_fields - set (req_secret_fields )
775
784
secret_fields = set (impacted_rel_fields ) - set (normal_fields )
776
785
@@ -779,8 +788,10 @@ def _process_secret_fields(
779
788
for group in secret_fieldnames_grouped :
780
789
# operation() should return nothing when all goes well
781
790
if group_result := operation (relation , group , secret_fields , * args , ** kwargs ):
782
- result .update (group_result )
783
- elif second_chance_as_normal_field :
791
+ # If "meaningful" data was returned, we take it. (Some 'operation'-s only return success/failure.)
792
+ if isinstance (group_result , dict ):
793
+ result .update (group_result )
794
+ else :
784
795
# If it wasn't found as a secret, let's give it a 2nd chance as "normal" field
785
796
# Needed when Juju3 Requires meets Juju2 Provider
786
797
normal_fields |= set (secret_fieldnames_grouped [group ])
@@ -999,12 +1010,12 @@ def _diff(self, event: RelationChangedEvent) -> Diff:
999
1010
@juju_secrets_only
1000
1011
def _add_relation_secret (
1001
1012
self , relation : Relation , content : Dict [str , str ], group_mapping : SecretGroup
1002
- ) -> Optional [ Secret ] :
1013
+ ) -> bool :
1003
1014
"""Add a new Juju Secret that will be registered in the relation databag."""
1004
1015
secret_field = self ._generate_secret_field_name (group_mapping )
1005
1016
if relation .data [self .local_app ].get (secret_field ):
1006
1017
logging .error ("Secret for relation %s already exists, not adding again" , relation .id )
1007
- return
1018
+ return False
1008
1019
1009
1020
label = self ._generate_secret_label (self .relation_name , relation .id , group_mapping )
1010
1021
secret = self .secrets .add (label , content , relation )
@@ -1013,57 +1024,76 @@ def _add_relation_secret(
1013
1024
if secret .meta and secret .meta .id :
1014
1025
relation .data [self .local_app ][secret_field ] = secret .meta .id
1015
1026
1027
+ # Return the content that was added
1028
+ return True
1029
+
1016
1030
@juju_secrets_only
1017
1031
def _update_relation_secret (
1018
1032
self , relation : Relation , content : Dict [str , str ], group_mapping : SecretGroup
1019
- ):
1033
+ ) -> bool :
1020
1034
"""Update the contents of an existing Juju Secret, referred in the relation databag."""
1021
1035
secret = self ._get_relation_secret (relation .id , group_mapping )
1022
1036
1023
1037
if not secret :
1024
1038
logging .error ("Can't update secret for relation %s" , relation .id )
1025
- return
1039
+ return False
1026
1040
1027
1041
old_content = secret .get_content ()
1028
1042
full_content = copy .deepcopy (old_content )
1029
1043
full_content .update (content )
1030
1044
secret .set_content (full_content )
1031
1045
1046
+ # Return True on success
1047
+ return True
1048
+
1032
1049
def _add_or_update_relation_secrets (
1033
1050
self ,
1034
1051
relation : Relation ,
1035
1052
group : SecretGroup ,
1036
1053
secret_fields : Set [str ],
1037
1054
data : Dict [str , str ],
1038
- ) -> None :
1055
+ ) -> bool :
1039
1056
"""Update contents for Secret group. If the Secret doesn't exist, create it."""
1040
1057
secret_content = self ._content_for_secret_group (data , secret_fields , group )
1041
1058
if self ._get_relation_secret (relation .id , group ):
1042
- self ._update_relation_secret (relation , secret_content , group )
1059
+ return self ._update_relation_secret (relation , secret_content , group )
1043
1060
else :
1044
- self ._add_relation_secret (relation , secret_content , group )
1061
+ return self ._add_relation_secret (relation , secret_content , group )
1045
1062
1046
1063
@juju_secrets_only
1047
1064
def _delete_relation_secret (
1048
1065
self , relation : Relation , group : SecretGroup , secret_fields : List [str ], fields : List [str ]
1049
- ):
1066
+ ) -> bool :
1050
1067
"""Update the contents of an existing Juju Secret, referred in the relation databag."""
1051
1068
secret = self ._get_relation_secret (relation .id , group )
1052
1069
1053
1070
if not secret :
1054
- logging .error ("Can't update secret for relation %s" , relation .id )
1055
- return
1071
+ logging .error ("Can't update secret for relation %s" , str ( relation .id ) )
1072
+ return False
1056
1073
1057
1074
old_content = secret .get_content ()
1058
1075
new_content = copy .deepcopy (old_content )
1059
1076
for field in fields :
1060
- new_content .pop (field )
1077
+ try :
1078
+ new_content .pop (field )
1079
+ except KeyError :
1080
+ logging .error (
1081
+ "Non-existing secret was attempted to be removed %s, %s" ,
1082
+ str (relation .id ),
1083
+ str (field ),
1084
+ )
1085
+ return False
1086
+
1061
1087
secret .set_content (new_content )
1062
1088
1089
+ # Remove secret from the relation if it's fully gone
1063
1090
if not new_content :
1064
1091
field = self ._generate_secret_field_name (group )
1065
1092
relation .data [self .local_app ].pop (field )
1066
1093
1094
+ # Return the content that was removed
1095
+ return True
1096
+
1067
1097
# Mandatory internal overrides
1068
1098
1069
1099
@juju_secrets_only
0 commit comments