@@ -41,22 +41,58 @@ struct VerityVolume {
4141
4242fn main ( ) -> Result < ( ) > {
4343 tracing_subscriber:: fmt ( ) . init ( ) ;
44- let compose_path = std:: env:: args_os ( )
45- . nth ( 1 )
46- . map ( PathBuf :: from)
47- . unwrap_or_else ( || PathBuf :: from ( "app-compose.json" ) ) ;
44+ let mut args = std:: env:: args_os ( ) . skip ( 1 ) ;
45+ let command = args
46+ . next ( )
47+ . context (
48+ "usage: dstack-volume <mount-all [COMPOSE] | mount COMPOSE INDEX | scan | status [COMPOSE]>" ,
49+ ) ?;
50+ match command. to_str ( ) {
51+ Some ( "mount-all" ) => mount_all (
52+ args. next ( )
53+ . map ( PathBuf :: from)
54+ . unwrap_or_else ( || PathBuf :: from ( "app-compose.json" ) ) ,
55+ ) ,
56+ Some ( "mount" ) => {
57+ let compose = args. next ( ) . context ( "mount requires COMPOSE and INDEX" ) ?;
58+ let index = args
59+ . next ( )
60+ . context ( "mount requires COMPOSE and INDEX" ) ?
61+ . to_str ( )
62+ . context ( "INDEX is not UTF-8" ) ?
63+ . parse ( )
64+ . context ( "invalid volume INDEX" ) ?;
65+ mount_one ( PathBuf :: from ( compose) , index)
66+ }
67+ Some ( "scan" ) => scan ( ) ,
68+ Some ( "status" ) => status (
69+ args. next ( )
70+ . map ( PathBuf :: from)
71+ . unwrap_or_else ( || PathBuf :: from ( "app-compose.json" ) ) ,
72+ ) ,
73+ _ => bail ! ( "unknown command {:?}" , command) ,
74+ }
75+ }
76+
77+ fn read_compose ( compose_path : & Path ) -> Result < AppCompose > {
4878 // Deserialize the complete shared type before probing any untrusted disk.
4979 // This validates roots and targets as part of parsing the measured compose.
50- let compose: AppCompose = serde_json:: from_slice ( & fs:: read ( & compose_path) ?)
51- . with_context ( || format ! ( "parsing {}" , compose_path. display( ) ) ) ?;
52- if compose. verity_volumes . is_empty ( ) {
53- return Ok ( ( ) ) ;
54- }
80+ serde_json:: from_slice ( & fs:: read ( compose_path) ?)
81+ . with_context ( || format ! ( "parsing {}" , compose_path. display( ) ) )
82+ }
5583
84+ fn prepare_volumes ( ) -> Result < Vec < VerityVolume > > {
5685 let _ = run_cmd ! ( modprobe dm-verity) ;
5786 let _ = run_cmd ! ( udevadm settle --timeout=5 ) ;
87+ discover_volumes ( )
88+ }
5889
59- let volumes = discover_volumes ( ) ?;
90+ fn mount_all ( compose_path : PathBuf ) -> Result < ( ) > {
91+ let compose = read_compose ( & compose_path) ?;
92+ if compose. verity_volumes . is_empty ( ) {
93+ return Ok ( ( ) ) ;
94+ }
95+ let volumes = prepare_volumes ( ) ?;
6096 info ! (
6197 found = volumes. len( ) ,
6298 requested = compose. verity_volumes. len( ) ,
@@ -74,6 +110,53 @@ fn main() -> Result<()> {
74110 Ok ( ( ) )
75111}
76112
113+ fn mount_one ( compose_path : PathBuf , index : usize ) -> Result < ( ) > {
114+ let compose = read_compose ( & compose_path) ?;
115+ let requested = compose
116+ . verity_volumes
117+ . get ( index)
118+ . with_context ( || format ! ( "volume index {index} is out of range" ) ) ?;
119+ let volumes = prepare_volumes ( ) ?;
120+ activate_requested ( index, requested, & volumes, & mut HashSet :: new ( ) ) . with_context ( || {
121+ format ! (
122+ "failed to activate required volume {index} at {}" ,
123+ requested. target. display( )
124+ )
125+ } )
126+ }
127+
128+ fn scan ( ) -> Result < ( ) > {
129+ for volume in prepare_volumes ( ) ? {
130+ println ! (
131+ "{}\t data={}\t hash={}" ,
132+ hex:: encode( volume. root_hash) ,
133+ volume. data. display( ) ,
134+ volume. hash. display( )
135+ ) ;
136+ }
137+ Ok ( ( ) )
138+ }
139+
140+ fn status ( compose_path : PathBuf ) -> Result < ( ) > {
141+ let compose = read_compose ( & compose_path) ?;
142+ let volumes = prepare_volumes ( ) ?;
143+ for ( index, requested) in compose. verity_volumes . iter ( ) . enumerate ( ) {
144+ let attached = volumes
145+ . iter ( )
146+ . any ( |volume| volume. root_hash == requested. verity_root ) ;
147+ let mapper_name = format ! ( "dstack-verity{index}" ) ;
148+ let active = Path :: new ( "/dev/mapper" ) . join ( & mapper_name) . exists ( )
149+ && mapping_root ( & mapper_name) ?
150+ . eq_ignore_ascii_case ( & hex:: encode ( requested. verity_root ) ) ;
151+ println ! (
152+ "{index}\t root={}\t target={}\t attached={attached}\t active={active}" ,
153+ hex:: encode( requested. verity_root) ,
154+ requested. target. display( )
155+ ) ;
156+ }
157+ Ok ( ( ) )
158+ }
159+
77160fn discover_volumes ( ) -> Result < Vec < VerityVolume > > {
78161 let mut found = Vec :: new ( ) ;
79162 let disks = list_disks ( ) ?;
0 commit comments