mz_catalog/durable/upgrade/
v89_to_v90.rs1use crate::durable::upgrade::MigrationAction;
11use crate::durable::upgrade::json_compatible::JsonCompatible;
12use crate::durable::upgrade::objects_v89 as v89;
13use crate::durable::upgrade::objects_v90 as v90;
14
15crate::json_compatible!(v89::ClusterKey with v90::ClusterKey);
16crate::json_compatible!(v89::ClusterReplicaKey with v90::ClusterReplicaKey);
17crate::json_compatible!(v89::ClusterId with v90::ClusterId);
18crate::json_compatible!(v89::RoleId with v90::RoleId);
19crate::json_compatible!(v89::MzAclItem with v90::MzAclItem);
20crate::json_compatible!(v89::ReplicaLogging with v90::ReplicaLogging);
21crate::json_compatible!(v89::ReplicaLocation with v90::ReplicaLocation);
22crate::json_compatible!(v89::OptimizerFeatureOverride with v90::OptimizerFeatureOverride);
23crate::json_compatible!(v89::ClusterSchedule with v90::ClusterSchedule);
24crate::json_compatible!(v89::AutoScalingStrategy with v90::AutoScalingStrategy);
25crate::json_compatible!(v89::BurstState with v90::BurstState);
26crate::json_compatible!(v89::ReconfigurationStatus with v90::ReconfigurationStatus);
27crate::json_compatible!(v89::OnTimeoutAction with v90::OnTimeoutAction);
28
29pub fn upgrade(
38 snapshot: Vec<v89::StateUpdateKind>,
39) -> Vec<MigrationAction<v89::StateUpdateKind, v90::StateUpdateKind>> {
40 let mut migrations = Vec::new();
41 for update in snapshot {
42 match update {
43 v89::StateUpdateKind::Cluster(old_cluster)
44 if matches!(
45 old_cluster.value.config.variant,
46 v89::ClusterVariant::Managed(_)
47 ) =>
48 {
49 let new_cluster = migrate_cluster(old_cluster.clone());
50 migrations.push(MigrationAction::Update(
51 v89::StateUpdateKind::Cluster(old_cluster),
52 v90::StateUpdateKind::Cluster(new_cluster),
53 ));
54 }
55 v89::StateUpdateKind::ClusterReplica(old_replica) => {
56 let new_replica = migrate_replica(old_replica.clone());
57 migrations.push(MigrationAction::Update(
58 v89::StateUpdateKind::ClusterReplica(old_replica),
59 v90::StateUpdateKind::ClusterReplica(new_replica),
60 ));
61 }
62 _ => {}
63 }
64 }
65 migrations
66}
67
68fn migrate_cluster(old: v89::Cluster) -> v90::Cluster {
69 let v89::Cluster { key, value } = old;
70 let v89::ClusterVariant::Managed(m) = value.config.variant else {
71 unreachable!("caller guards on the managed variant");
72 };
73 v90::Cluster {
74 key: JsonCompatible::convert(&key),
75 value: v90::ClusterValue {
76 name: value.name,
77 owner_id: JsonCompatible::convert(&value.owner_id),
78 privileges: value
79 .privileges
80 .iter()
81 .map(JsonCompatible::convert)
82 .collect(),
83 config: v90::ClusterConfig {
84 workload_class: value.config.workload_class,
85 variant: v90::ClusterVariant::Managed(migrate_managed(m)),
86 },
87 },
88 }
89}
90
91fn migrate_managed(m: v89::ManagedCluster) -> v90::ManagedCluster {
92 v90::ManagedCluster {
93 size: m.size,
94 replication_factor: m.replication_factor,
95 availability_zones: m.availability_zones,
96 logging: JsonCompatible::convert(&m.logging),
97 arrangement_compression: false,
98 optimizer_feature_overrides: m
99 .optimizer_feature_overrides
100 .iter()
101 .map(JsonCompatible::convert)
102 .collect(),
103 schedule: JsonCompatible::convert(&m.schedule),
104 auto_scaling_strategy: m
105 .auto_scaling_strategy
106 .as_ref()
107 .map(JsonCompatible::convert),
108 reconfiguration: m.reconfiguration.map(migrate_reconfiguration),
109 burst: m.burst.as_ref().map(JsonCompatible::convert),
110 }
111}
112
113fn migrate_reconfiguration(old: v89::ReconfigurationState) -> v90::ReconfigurationState {
114 let v89::ReconfigurationTarget {
115 size,
116 replication_factor,
117 availability_zones,
118 logging,
119 } = old.target;
120 v90::ReconfigurationState {
121 target: v90::ReconfigurationTarget {
122 size,
123 replication_factor,
124 availability_zones,
125 logging: JsonCompatible::convert(&logging),
126 arrangement_compression: false,
127 },
128 deadline: old.deadline,
129 on_timeout: JsonCompatible::convert(&old.on_timeout),
130 status: JsonCompatible::convert(&old.status),
131 }
132}
133
134fn migrate_replica(old: v89::ClusterReplica) -> v90::ClusterReplica {
135 let v89::ClusterReplica { key, value } = old;
136 let v89::ReplicaConfig { logging, location } = value.config;
137 v90::ClusterReplica {
138 key: JsonCompatible::convert(&key),
139 value: v90::ClusterReplicaValue {
140 cluster_id: JsonCompatible::convert(&value.cluster_id),
141 name: value.name,
142 config: v90::ReplicaConfig {
143 logging: JsonCompatible::convert(&logging),
144 location: JsonCompatible::convert(&location),
145 arrangement_compression: false,
146 },
147 owner_id: JsonCompatible::convert(&value.owner_id),
148 },
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use crate::durable::upgrade::MigrationAction;
155 use crate::durable::upgrade::v89_to_v90::upgrade;
156 use crate::durable::upgrade::{objects_v89 as v89, objects_v90 as v90};
157
158 fn managed_cluster(id: u64) -> v89::Cluster {
159 v89::Cluster {
160 key: v89::ClusterKey {
161 id: v89::ClusterId::User(id),
162 },
163 value: v89::ClusterValue {
164 name: format!("cluster{id}"),
165 owner_id: v89::RoleId::User(1),
166 privileges: Vec::new(),
167 config: v89::ClusterConfig {
168 workload_class: None,
169 variant: v89::ClusterVariant::Managed(v89::ManagedCluster {
170 size: "small".to_string(),
171 replication_factor: 1,
172 availability_zones: vec!["az1".to_string()],
173 logging: v89::ReplicaLogging {
174 log_logging: false,
175 interval: None,
176 },
177 optimizer_feature_overrides: Vec::new(),
178 schedule: v89::ClusterSchedule::Manual,
179 auto_scaling_strategy: None,
180 reconfiguration: None,
181 burst: None,
182 }),
183 },
184 },
185 }
186 }
187
188 fn unmanaged_cluster(id: u64) -> v89::Cluster {
189 v89::Cluster {
190 key: v89::ClusterKey {
191 id: v89::ClusterId::User(id),
192 },
193 value: v89::ClusterValue {
194 name: format!("cluster{id}"),
195 owner_id: v89::RoleId::User(1),
196 privileges: Vec::new(),
197 config: v89::ClusterConfig {
198 workload_class: None,
199 variant: v89::ClusterVariant::Unmanaged,
200 },
201 },
202 }
203 }
204
205 fn replica(id: u64) -> v89::ClusterReplica {
206 v89::ClusterReplica {
207 key: v89::ClusterReplicaKey {
208 id: v89::ReplicaId::User(id),
209 },
210 value: v89::ClusterReplicaValue {
211 cluster_id: v89::ClusterId::User(1),
212 name: format!("r{id}"),
213 config: v89::ReplicaConfig {
214 logging: v89::ReplicaLogging {
215 log_logging: false,
216 interval: None,
217 },
218 location: v89::ReplicaLocation::Managed(v89::ManagedLocation {
219 size: "small".to_string(),
220 availability_zones: vec!["az1".to_string()],
221 billed_as: None,
222 internal: false,
223 pending: false,
224 }),
225 },
226 owner_id: v89::RoleId::User(1),
227 },
228 }
229 }
230
231 #[mz_ore::test]
232 fn backfills_managed_cluster_and_replica_as_false() {
233 let migrations = upgrade(vec![
234 v89::StateUpdateKind::Cluster(managed_cluster(1)),
235 v89::StateUpdateKind::Cluster(unmanaged_cluster(2)),
236 v89::StateUpdateKind::ClusterReplica(replica(1)),
237 ]);
238 assert_eq!(migrations.len(), 2);
240
241 let MigrationAction::Update(_, v90::StateUpdateKind::Cluster(cluster)) = &migrations[0]
242 else {
243 panic!("expected a cluster update");
244 };
245 let v90::ClusterVariant::Managed(managed) = &cluster.value.config.variant else {
246 panic!("expected a managed cluster");
247 };
248 assert!(!managed.arrangement_compression);
249
250 let MigrationAction::Update(_, v90::StateUpdateKind::ClusterReplica(replica)) =
251 &migrations[1]
252 else {
253 panic!("expected a replica update");
254 };
255 assert!(!replica.value.config.arrangement_compression);
256 }
257}