Skip to main content

microsandbox_migration/
schema_metadata.rs

1//! Static metadata for downgrade planning.
2//!
3//! `Migrator::migrations()` owns the executable migration order. This module
4//! keeps the user-facing downgrade metadata in the same crate so release checks
5//! can ensure every migration has an explicit reversibility and cache-impact
6//! decision before a new binary ships.
7
8//--------------------------------------------------------------------------------------------------
9// Constants
10//--------------------------------------------------------------------------------------------------
11
12/// Version of the hidden schema-baseline JSON shape emitted by the CLI.
13pub const SCHEMA_BASELINE_FORMAT_VERSION: u32 = 1;
14
15/// Oldest release supported by the downgrade flow.
16pub const DOWNGRADE_FLOOR: &str = "0.6.0";
17
18/// Migration that introduced the DB-backed maintenance lease table.
19pub const MAINTENANCE_LEASE_MIGRATION_ID: &str = "m20260621_000002_create_maintenance_lease";
20
21/// Migration that introduced desired-vs-active sandbox config tracking.
22pub const ACTIVE_CONFIG_MIGRATION_ID: &str = "m20260703_000001_add_sandbox_active_config";
23
24/// Migration that adds payload scope metadata to the snapshot index.
25pub const SNAPSHOT_SCOPE_MIGRATION_ID: &str = "m20260714_000001_add_snapshot_scope";
26
27/// Migration that projects final snapshot state and journals legacy conversion.
28pub const SNAPSHOT_ARTIFACT_TRANSITION_MIGRATION_ID: &str =
29    "m20260723_000001_snapshot_artifact_transition";
30
31/// Frozen migration baseline for the transitional 0.6.0 release.
32///
33/// The released 0.6.0 binary predates `msb __schema-baseline --json`, so
34/// downgrade uses this fixture when inspecting that exact target. Do not extend
35/// this list when adding later migrations; future targets should answer with
36/// their own hidden baseline command.
37pub const BASELINE_0_6_0_MIGRATIONS: &[&str] = &[
38    "m20260305_000001_create_image_tables",
39    "m20260305_000002_create_sandbox_tables",
40    "m20260305_000003_create_storage_tables",
41    "m20260305_000004_create_sandbox_images_table",
42    "m20260410_000001_erofs_image_schema",
43    "m20260501_000001_create_snapshot_index",
44    "m20260517_000001_drop_sandbox_metric",
45    "m20260527_000001_migrate_oci_rootfs_source",
46    "m20260531_000001_create_sandbox_labels",
47    "m20260531_000002_index_sandbox_labels_key_value",
48    "m20260606_000001_named_volume_kinds",
49    "m20260621_000001_add_sandbox_ephemeral",
50    MAINTENANCE_LEASE_MIGRATION_ID,
51];
52
53/// Metadata for every migration in `Migrator::migrations()` order.
54pub const MIGRATION_METADATA: &[MigrationMetadata] = &[
55    MigrationMetadata {
56        id: "m20260305_000001_create_image_tables",
57        reversible: true,
58        affects_cache: true,
59        affects_user_data: false,
60        summary: "remove legacy OCI image catalog tables",
61    },
62    MigrationMetadata {
63        id: "m20260305_000002_create_sandbox_tables",
64        reversible: true,
65        affects_cache: false,
66        affects_user_data: false,
67        summary: "remove sandbox and run tables",
68    },
69    MigrationMetadata {
70        id: "m20260305_000003_create_storage_tables",
71        reversible: true,
72        affects_cache: false,
73        affects_user_data: false,
74        summary: "remove volume and snapshot storage tables",
75    },
76    MigrationMetadata {
77        id: "m20260305_000004_create_sandbox_images_table",
78        reversible: true,
79        affects_cache: true,
80        affects_user_data: false,
81        summary: "remove sandbox image references",
82    },
83    MigrationMetadata {
84        id: "m20260410_000001_erofs_image_schema",
85        reversible: true,
86        affects_cache: true,
87        affects_user_data: false,
88        summary: "remove EROFS rootfs catalog tables",
89    },
90    MigrationMetadata {
91        id: "m20260501_000001_create_snapshot_index",
92        reversible: true,
93        affects_cache: false,
94        affects_user_data: false,
95        summary: "remove snapshot index table",
96    },
97    MigrationMetadata {
98        id: "m20260517_000001_drop_sandbox_metric",
99        reversible: false,
100        affects_cache: false,
101        affects_user_data: false,
102        summary: "restore legacy sandbox metrics table",
103    },
104    MigrationMetadata {
105        id: "m20260527_000001_migrate_oci_rootfs_source",
106        reversible: false,
107        affects_cache: false,
108        affects_user_data: false,
109        summary: "rewrite OCI rootfs config back to the legacy string shape",
110    },
111    MigrationMetadata {
112        id: "m20260531_000001_create_sandbox_labels",
113        reversible: true,
114        affects_cache: false,
115        affects_user_data: false,
116        summary: "remove sandbox labels table",
117    },
118    MigrationMetadata {
119        id: "m20260531_000002_index_sandbox_labels_key_value",
120        reversible: true,
121        affects_cache: false,
122        affects_user_data: false,
123        summary: "remove sandbox label key/value index",
124    },
125    MigrationMetadata {
126        id: "m20260606_000001_named_volume_kinds",
127        reversible: true,
128        affects_cache: false,
129        affects_user_data: false,
130        summary: "remove named volume kind columns and attachments",
131    },
132    MigrationMetadata {
133        id: "m20260621_000001_add_sandbox_ephemeral",
134        reversible: true,
135        affects_cache: false,
136        affects_user_data: false,
137        summary: "remove sandbox ephemeral flag",
138    },
139    MigrationMetadata {
140        id: MAINTENANCE_LEASE_MIGRATION_ID,
141        reversible: true,
142        affects_cache: false,
143        affects_user_data: false,
144        summary: "remove maintenance lease table",
145    },
146    MigrationMetadata {
147        id: ACTIVE_CONFIG_MIGRATION_ID,
148        reversible: true,
149        affects_cache: false,
150        affects_user_data: false,
151        summary: "remove active sandbox config snapshots",
152    },
153    MigrationMetadata {
154        id: "m20260708_000001_migrate_bind_rootfs_source",
155        reversible: true,
156        affects_cache: false,
157        affects_user_data: true,
158        summary: "rewrite bind rootfs config back to the legacy string shape",
159    },
160    MigrationMetadata {
161        id: "m20260710_000001_migrate_root_disk",
162        reversible: true,
163        affects_cache: false,
164        affects_user_data: true,
165        summary: "rewrite root disk config back to the upper size shape",
166    },
167    MigrationMetadata {
168        id: SNAPSHOT_SCOPE_MIGRATION_ID,
169        reversible: true,
170        affects_cache: false,
171        affects_user_data: false,
172        summary: "remove snapshot scope index metadata",
173    },
174    MigrationMetadata {
175        id: SNAPSHOT_ARTIFACT_TRANSITION_MIGRATION_ID,
176        reversible: true,
177        affects_cache: false,
178        affects_user_data: true,
179        summary: "reverse final snapshot descriptors before removing migration state",
180    },
181];
182
183//--------------------------------------------------------------------------------------------------
184// Types
185//--------------------------------------------------------------------------------------------------
186
187/// Downgrade metadata for one migration.
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub struct MigrationMetadata {
190    /// Migration identifier returned by `MigrationName::name()`.
191    pub id: &'static str,
192
193    /// Whether `down()` actually restores a target-compatible schema/state.
194    pub reversible: bool,
195
196    /// Whether rolling this migration back invalidates re-pullable image cache
197    /// contents on disk.
198    pub affects_cache: bool,
199
200    /// Whether rolling this migration back may leave snapshots or disk-backed
201    /// named volumes in a format the target release cannot read.
202    pub affects_user_data: bool,
203
204    /// Short human-readable summary used in destructive downgrade prompts.
205    pub summary: &'static str,
206}
207
208//--------------------------------------------------------------------------------------------------
209// Functions
210//--------------------------------------------------------------------------------------------------
211
212/// Return all migration identifiers in schema order.
213pub fn migration_ids() -> impl Iterator<Item = &'static str> {
214    MIGRATION_METADATA.iter().map(|metadata| metadata.id)
215}
216
217//--------------------------------------------------------------------------------------------------
218// Tests
219//--------------------------------------------------------------------------------------------------
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224    use crate::{Migrator, MigratorTrait};
225
226    #[test]
227    fn metadata_matches_migrator_order() {
228        let migrations = Migrator::migrations();
229        let migrator_ids: Vec<_> = migrations
230            .iter()
231            .map(|migration| migration.name().to_string())
232            .collect();
233        let metadata_ids: Vec<_> = migration_ids().map(str::to_string).collect();
234
235        assert_eq!(metadata_ids, migrator_ids);
236    }
237
238    #[test]
239    fn frozen_0_6_0_baseline_is_current_prefix() {
240        let metadata_ids: Vec<_> = migration_ids().collect();
241        assert!(metadata_ids.starts_with(BASELINE_0_6_0_MIGRATIONS));
242    }
243}