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/// Frozen migration baseline for the transitional 0.6.0 release.
22///
23/// The released 0.6.0 binary predates `msb __schema-baseline --json`, so
24/// downgrade uses this fixture when inspecting that exact target. Do not extend
25/// this list when adding later migrations; future targets should answer with
26/// their own hidden baseline command.
27pub const BASELINE_0_6_0_MIGRATIONS: &[&str] = &[
28    "m20260305_000001_create_image_tables",
29    "m20260305_000002_create_sandbox_tables",
30    "m20260305_000003_create_storage_tables",
31    "m20260305_000004_create_sandbox_images_table",
32    "m20260410_000001_erofs_image_schema",
33    "m20260501_000001_create_snapshot_index",
34    "m20260517_000001_drop_sandbox_metric",
35    "m20260527_000001_migrate_oci_rootfs_source",
36    "m20260531_000001_create_sandbox_labels",
37    "m20260531_000002_index_sandbox_labels_key_value",
38    "m20260606_000001_named_volume_kinds",
39    "m20260621_000001_add_sandbox_ephemeral",
40    MAINTENANCE_LEASE_MIGRATION_ID,
41];
42
43/// Metadata for every migration in `Migrator::migrations()` order.
44pub const MIGRATION_METADATA: &[MigrationMetadata] = &[
45    MigrationMetadata {
46        id: "m20260305_000001_create_image_tables",
47        reversible: true,
48        affects_cache: true,
49        affects_user_data: false,
50        summary: "remove legacy OCI image catalog tables",
51    },
52    MigrationMetadata {
53        id: "m20260305_000002_create_sandbox_tables",
54        reversible: true,
55        affects_cache: false,
56        affects_user_data: false,
57        summary: "remove sandbox and run tables",
58    },
59    MigrationMetadata {
60        id: "m20260305_000003_create_storage_tables",
61        reversible: true,
62        affects_cache: false,
63        affects_user_data: false,
64        summary: "remove volume and snapshot storage tables",
65    },
66    MigrationMetadata {
67        id: "m20260305_000004_create_sandbox_images_table",
68        reversible: true,
69        affects_cache: true,
70        affects_user_data: false,
71        summary: "remove sandbox image references",
72    },
73    MigrationMetadata {
74        id: "m20260410_000001_erofs_image_schema",
75        reversible: true,
76        affects_cache: true,
77        affects_user_data: false,
78        summary: "remove EROFS rootfs catalog tables",
79    },
80    MigrationMetadata {
81        id: "m20260501_000001_create_snapshot_index",
82        reversible: true,
83        affects_cache: false,
84        affects_user_data: false,
85        summary: "remove snapshot index table",
86    },
87    MigrationMetadata {
88        id: "m20260517_000001_drop_sandbox_metric",
89        reversible: false,
90        affects_cache: false,
91        affects_user_data: false,
92        summary: "restore legacy sandbox metrics table",
93    },
94    MigrationMetadata {
95        id: "m20260527_000001_migrate_oci_rootfs_source",
96        reversible: false,
97        affects_cache: false,
98        affects_user_data: false,
99        summary: "rewrite OCI rootfs config back to the legacy string shape",
100    },
101    MigrationMetadata {
102        id: "m20260531_000001_create_sandbox_labels",
103        reversible: true,
104        affects_cache: false,
105        affects_user_data: false,
106        summary: "remove sandbox labels table",
107    },
108    MigrationMetadata {
109        id: "m20260531_000002_index_sandbox_labels_key_value",
110        reversible: true,
111        affects_cache: false,
112        affects_user_data: false,
113        summary: "remove sandbox label key/value index",
114    },
115    MigrationMetadata {
116        id: "m20260606_000001_named_volume_kinds",
117        reversible: true,
118        affects_cache: false,
119        affects_user_data: false,
120        summary: "remove named volume kind columns and attachments",
121    },
122    MigrationMetadata {
123        id: "m20260621_000001_add_sandbox_ephemeral",
124        reversible: true,
125        affects_cache: false,
126        affects_user_data: false,
127        summary: "remove sandbox ephemeral flag",
128    },
129    MigrationMetadata {
130        id: MAINTENANCE_LEASE_MIGRATION_ID,
131        reversible: true,
132        affects_cache: false,
133        affects_user_data: false,
134        summary: "remove maintenance lease table",
135    },
136];
137
138//--------------------------------------------------------------------------------------------------
139// Types
140//--------------------------------------------------------------------------------------------------
141
142/// Downgrade metadata for one migration.
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub struct MigrationMetadata {
145    /// Migration identifier returned by `MigrationName::name()`.
146    pub id: &'static str,
147
148    /// Whether `down()` actually restores a target-compatible schema/state.
149    pub reversible: bool,
150
151    /// Whether rolling this migration back invalidates re-pullable image cache
152    /// contents on disk.
153    pub affects_cache: bool,
154
155    /// Whether rolling this migration back may leave snapshots or disk-backed
156    /// named volumes in a format the target release cannot read.
157    pub affects_user_data: bool,
158
159    /// Short human-readable summary used in destructive downgrade prompts.
160    pub summary: &'static str,
161}
162
163//--------------------------------------------------------------------------------------------------
164// Functions
165//--------------------------------------------------------------------------------------------------
166
167/// Return all migration identifiers in schema order.
168pub fn migration_ids() -> impl Iterator<Item = &'static str> {
169    MIGRATION_METADATA.iter().map(|metadata| metadata.id)
170}
171
172//--------------------------------------------------------------------------------------------------
173// Tests
174//--------------------------------------------------------------------------------------------------
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179    use crate::{Migrator, MigratorTrait};
180
181    #[test]
182    fn metadata_matches_migrator_order() {
183        let migrations = Migrator::migrations();
184        let migrator_ids: Vec<_> = migrations
185            .iter()
186            .map(|migration| migration.name().to_string())
187            .collect();
188        let metadata_ids: Vec<_> = migration_ids().map(str::to_string).collect();
189
190        assert_eq!(metadata_ids, migrator_ids);
191    }
192
193    #[test]
194    fn frozen_0_6_0_baseline_is_current_prefix() {
195        let metadata_ids: Vec<_> = migration_ids().collect();
196        assert!(metadata_ids.starts_with(BASELINE_0_6_0_MIGRATIONS));
197    }
198}