13
13
CollectStatusEvent ,
14
14
ConfigChangedEvent ,
15
15
InstallEvent ,
16
+ ModelError ,
16
17
Object ,
18
+ SecretChangedEvent ,
19
+ SecretNotFoundError ,
17
20
StartEvent ,
18
21
UpdateStatusEvent ,
19
22
)
@@ -60,6 +63,7 @@ def __init__(
60
63
self .framework .observe (self .charm .on .start , self ._on_start )
61
64
self .framework .observe (self .charm .on .install , self ._on_install )
62
65
self .framework .observe (self .charm .on .config_changed , self ._on_config_changed )
66
+ self .framework .observe (self .charm .on .secret_changed , self ._on_secret_changed )
63
67
self .framework .observe (self .charm .on .update_status , self ._on_update_status )
64
68
self .framework .observe (self .charm .on .collect_unit_status , self ._on_collect_unit_status )
65
69
self .framework .observe (self .charm .on .collect_app_status , self ._on_collect_app_status )
@@ -91,21 +95,20 @@ def _on_start(self, event: StartEvent) -> None:
91
95
return
92
96
93
97
try :
94
- if self .charm .unit .is_leader ():
95
- self .state .cluster .cluster_name = self .charm .config .cluster_name
96
- self .state .cluster .seeds = [self .state .unit .peer_url ]
97
98
self .config_manager .render_env (
98
99
cassandra_limit_memory_mb = 1024 if self .charm .config .profile == "testing" else None
99
100
)
101
+ if self .charm .unit .is_leader ():
102
+ self .state .cluster .cluster_name = self .charm .config .cluster_name
103
+ self .state .cluster .seeds = [self .state .unit .peer_url ]
104
+ self .state .cluster .cassandra_password_secret = self ._acquire_cassandra_password ()
105
+ self ._start_password_change (event )
106
+ return
100
107
except ValidationError as e :
101
108
logger .debug (f"Config haven't passed validation: { e } " )
102
109
event .defer ()
103
110
return
104
111
105
- if not self .state .cluster .cassandra_password_secret :
106
- self ._start_password_change (event )
107
- return
108
-
109
112
self .config_manager .render_cassandra_config (
110
113
cluster_name = self .state .cluster .cluster_name ,
111
114
listen_address = self .state .unit .ip ,
@@ -118,9 +121,27 @@ def _on_start(self, event: StartEvent) -> None:
118
121
)
119
122
self .charm .on [str (self .bootstrap_manager .name )].acquire_lock .emit ()
120
123
124
+ def _acquire_cassandra_password (self ) -> str :
125
+ if self .charm .config .system_users :
126
+ try :
127
+ if (
128
+ password := self .model .get_secret (id = self .charm .config .system_users )
129
+ .get_content (refresh = True )
130
+ .get ("cassandra-password" )
131
+ ):
132
+ return password
133
+ except SecretNotFoundError :
134
+ # TODO: logging.
135
+ pass
136
+ except ModelError :
137
+ pass
138
+ if self .state .cluster .cassandra_password_secret :
139
+ return self .state .cluster .cassandra_password_secret
140
+ return self .workload .generate_password ()
141
+
121
142
def _start_password_change (self , event : StartEvent ) -> None :
122
143
self .config_manager .render_cassandra_config (
123
- cluster_name = self .charm . config .cluster_name ,
144
+ cluster_name = self .state . cluster .cluster_name ,
124
145
listen_address = "127.0.0.1" ,
125
146
seeds = ["127.0.0.1:7000" ],
126
147
authentication = False ,
@@ -133,26 +154,31 @@ def _finalize_password_change(self, event: StartEvent) -> None:
133
154
if not self .cluster_manager .is_healthy :
134
155
event .defer ()
135
156
return
136
- password = self .workload . generate_password ()
137
- self . database_manager . update_system_user_password ( "cassandra" , password )
138
- self . state . cluster . cassandra_password_secret = password
139
- self .cluster_manager .flush_tables ( "system_auth" , [ "roles" ] )
157
+ self .database_manager . update_system_user_password (
158
+ "cassandra" , self . state . cluster . cassandra_password_secret
159
+ )
160
+ self .cluster_manager .prepare_shutdown ( )
140
161
self .config_manager .render_cassandra_config (
141
- cluster_name = self .charm . config .cluster_name ,
162
+ cluster_name = self .state . cluster .cluster_name ,
142
163
listen_address = self .state .unit .ip ,
143
164
seeds = self .state .cluster .seeds ,
144
165
authentication = True ,
145
166
)
146
167
self .charm .on [str (self .bootstrap_manager .name )].acquire_lock .emit ()
147
168
148
- def _on_config_changed (self , _ : ConfigChangedEvent ) -> None :
149
- # TODO: add peer relation change hook for subordinates to update leader address too
150
- if self .state .unit .workload_state not in [
151
- UnitWorkloadState .STARTING ,
152
- UnitWorkloadState .ACTIVE ,
153
- ]:
169
+ def _on_config_changed (self , event : ConfigChangedEvent ) -> None :
170
+ if self .state .unit .workload_state == UnitWorkloadState .INSTALLING :
171
+ return
172
+ if self .state .unit .workload_state != UnitWorkloadState .ACTIVE :
173
+ event .defer ()
154
174
return
155
175
try :
176
+ if self .charm .unit .is_leader () and self .state .cluster .cassandra_password_secret != (
177
+ password := self ._acquire_cassandra_password ()
178
+ ):
179
+ self .database_manager .update_system_user_password ("cassandra" , password )
180
+ self .state .cluster .cassandra_password_secret = password
181
+ self .cluster_manager .prepare_shutdown ()
156
182
# TODO: cluster_name change
157
183
self .config_manager .render_env (
158
184
cassandra_limit_memory_mb = 1024 if self .charm .config .profile == "testing" else None
@@ -171,8 +197,30 @@ def _on_config_changed(self, _: ConfigChangedEvent) -> None:
171
197
self .state .unit .peer_tls .rotation = False
172
198
self .state .unit .client_tls .rotation = False
173
199
174
- if self .state .unit .workload_state == UnitWorkloadState .ACTIVE :
175
- self .charm .on [str (self .bootstrap_manager .name )].acquire_lock .emit ()
200
+ self .charm .on [str (self .bootstrap_manager .name )].acquire_lock .emit ()
201
+
202
+ def _on_secret_changed (self , event : SecretChangedEvent ) -> None :
203
+ if not self .charm .unit .is_leader ():
204
+ return
205
+
206
+ if self .state .unit .workload_state == UnitWorkloadState .INSTALLING :
207
+ return
208
+
209
+ try :
210
+ if event .secret .id != self .charm .config .system_users :
211
+ return
212
+
213
+ if self .state .unit .workload_state != UnitWorkloadState .ACTIVE :
214
+ event .defer ()
215
+ return
216
+
217
+ if self .state .cluster .cassandra_password_secret != (
218
+ password := self ._acquire_cassandra_password ()
219
+ ):
220
+ self .database_manager .update_system_user_password ("cassandra" , password )
221
+ self .state .cluster .cassandra_password_secret = password
222
+ except ValidationError :
223
+ return
176
224
177
225
def _on_update_status (self , _ : UpdateStatusEvent ) -> None :
178
226
# TODO: add peer relation change hook for subordinates to update leader address too
0 commit comments