12
12
DependencyModel ,
13
13
UpgradeGrantedEvent ,
14
14
)
15
- from ops .model import ActiveStatus , MaintenanceStatus , WaitingStatus
15
+ from ops .model import MaintenanceStatus , RelationDataContent , WaitingStatus
16
16
from pydantic import BaseModel
17
17
from tenacity import RetryError , Retrying , stop_after_attempt , wait_fixed
18
18
from typing_extensions import override
19
19
20
- from constants import SNAP_PACKAGES
20
+ from constants import APP_SCOPE , MONITORING_PASSWORD_KEY , MONITORING_USER , SNAP_PACKAGES
21
+ from utils import new_password
21
22
22
23
logger = logging .getLogger (__name__ )
23
24
@@ -26,6 +27,7 @@ class PostgreSQLDependencyModel(BaseModel):
26
27
"""PostgreSQL dependencies model."""
27
28
28
29
charm : DependencyModel
30
+ snap : DependencyModel
29
31
30
32
31
33
def get_postgresql_dependencies_model () -> PostgreSQLDependencyModel :
@@ -42,6 +44,7 @@ def __init__(self, charm, model: BaseModel, **kwargs) -> None:
42
44
"""Initialize the class."""
43
45
super ().__init__ (charm , model , ** kwargs )
44
46
self .charm = charm
47
+ self ._on_upgrade_charm_check_legacy ()
45
48
46
49
@override
47
50
def build_upgrade_stack (self ) -> List [int ]:
@@ -77,9 +80,56 @@ def log_rollback_instructions(self) -> None:
77
80
"Run `juju refresh --revision <previous-revision> postgresql` to initiate the rollback"
78
81
)
79
82
83
+ def _on_upgrade_charm_check_legacy (self ) -> None :
84
+ if not self .peer_relation or len (self .app_units ) < len (self .charm .app_units ):
85
+ logger .debug ("Wait all units join the upgrade relation" )
86
+ return
87
+
88
+ if self .state :
89
+ # If state set, upgrade is supported. Just set the snap information
90
+ # in the dependencies, as it's missing in the first revisions that
91
+ # support upgrades.
92
+ dependencies = self .peer_relation .data [self .charm .app ].get ("dependencies" )
93
+ if (
94
+ self .charm .unit .is_leader ()
95
+ and dependencies is not None
96
+ and "snap" not in json .loads (dependencies )
97
+ ):
98
+ fixed_dependencies = json .loads (dependencies )
99
+ fixed_dependencies ["snap" ] = {
100
+ "dependencies" : {},
101
+ "name" : "charmed-postgresql" ,
102
+ "upgrade_supported" : "^14" ,
103
+ "version" : "14.9" ,
104
+ }
105
+ self .peer_relation .data [self .charm .app ].update (
106
+ {"dependencies" : json .dumps (fixed_dependencies )}
107
+ )
108
+ return
109
+
110
+ if not self .charm .unit .is_leader ():
111
+ # set ready state on non-leader units
112
+ self .unit_upgrade_data .update ({"state" : "ready" })
113
+ return
114
+
115
+ peers_state = list (filter (lambda state : state != "" , self .unit_states ))
116
+
117
+ if len (peers_state ) == len (self .peer_relation .units ) and (
118
+ set (peers_state ) == {"ready" } or len (peers_state ) == 0
119
+ ):
120
+ if self .charm ._patroni .member_started :
121
+ # All peers have set the state to ready
122
+ self .unit_upgrade_data .update ({"state" : "ready" })
123
+ self ._prepare_upgrade_from_legacy ()
124
+ getattr (self .on , "upgrade_charm" ).emit ()
125
+
80
126
@override
81
127
def _on_upgrade_granted (self , event : UpgradeGrantedEvent ) -> None :
82
128
# Refresh the charmed PostgreSQL snap and restart the database.
129
+ # Update the configuration.
130
+ self .charm .unit .status = MaintenanceStatus ("updating configuration" )
131
+ self .charm .update_config ()
132
+
83
133
self .charm .unit .status = MaintenanceStatus ("refreshing the snap" )
84
134
self .charm ._install_snap_packages (packages = SNAP_PACKAGES , refresh = True )
85
135
@@ -91,6 +141,14 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None:
91
141
self .charm ._setup_exporter ()
92
142
self .charm .backup .start_stop_pgbackrest_service ()
93
143
144
+ try :
145
+ self .charm .unit .set_workload_version (
146
+ self .charm ._patroni .get_postgresql_version () or "unset"
147
+ )
148
+ except TypeError :
149
+ # Don't fail on this, just log it.
150
+ logger .warning ("Failed to get PostgreSQL version" )
151
+
94
152
# Wait until the database initialise.
95
153
self .charm .unit .status = WaitingStatus ("waiting for database initialisation" )
96
154
try :
@@ -110,7 +168,6 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None:
110
168
raise Exception ()
111
169
112
170
self .set_unit_completed ()
113
- self .charm .unit .status = ActiveStatus ()
114
171
115
172
# Ensures leader gets its own relation-changed when it upgrades
116
173
if self .charm .unit .is_leader ():
@@ -144,3 +201,36 @@ def pre_upgrade_check(self) -> None:
144
201
"a backup is being created" ,
145
202
"wait for the backup creation to finish before starting the upgrade" ,
146
203
)
204
+
205
+ def _prepare_upgrade_from_legacy (self ) -> None :
206
+ """Prepare upgrade from legacy charm without upgrade support.
207
+
208
+ Assumes run on leader unit only.
209
+ """
210
+ logger .warning ("Upgrading from unsupported version" )
211
+
212
+ # Populate app upgrade databag to allow upgrade procedure
213
+ logger .debug ("Building upgrade stack" )
214
+ upgrade_stack = self .build_upgrade_stack ()
215
+ logger .debug (f"Upgrade stack: { upgrade_stack } " )
216
+ self .upgrade_stack = upgrade_stack
217
+ logger .debug ("Persisting dependencies to upgrade relation data..." )
218
+ self .peer_relation .data [self .charm .app ].update (
219
+ {"dependencies" : json .dumps (self .dependency_model .dict ())}
220
+ )
221
+ if self .charm .get_secret (APP_SCOPE , MONITORING_PASSWORD_KEY ) is None :
222
+ self .charm .set_secret (APP_SCOPE , MONITORING_PASSWORD_KEY , new_password ())
223
+ users = self .charm .postgresql .list_users ()
224
+ if MONITORING_USER not in users :
225
+ # Create the monitoring user.
226
+ self .charm .postgresql .create_user (
227
+ MONITORING_USER ,
228
+ self .charm .get_secret (APP_SCOPE , MONITORING_PASSWORD_KEY ),
229
+ extra_user_roles = "pg_monitor" ,
230
+ )
231
+ self .charm .postgresql .set_up_database ()
232
+
233
+ @property
234
+ def unit_upgrade_data (self ) -> RelationDataContent :
235
+ """Return the application upgrade data."""
236
+ return self .peer_relation .data [self .charm .unit ]
0 commit comments