11// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
22// SPDX-License-Identifier: Apache-2.0
33
4- use crate :: { FileCommand , IMAGE_DIR } ;
4+ use crate :: { FileCommand , PulledImageData , IMAGE_DIR } ;
55use feos_proto:: image_service:: { ImageInfo , ImageState } ;
6+ use flate2:: read:: GzDecoder ;
67use log:: { error, info, warn} ;
78use serde:: { Deserialize , Serialize } ;
89use std:: collections:: HashMap ;
10+ use std:: io:: Cursor ;
911use std:: path:: Path ;
10- use tokio:: { fs, io:: AsyncWriteExt , sync:: mpsc} ;
12+ use tar:: Archive ;
13+ use tokio:: { fs, sync:: mpsc} ;
1114
1215#[ derive( Serialize , Deserialize ) ]
1316struct ImageMetadata {
@@ -56,7 +59,7 @@ impl FileStore {
5659 } => {
5760 info ! ( "FileStore: Storing image {image_uuid}" ) ;
5861 let final_dir = Path :: new ( IMAGE_DIR ) . join ( & image_uuid) ;
59- let result = Self :: store_image_impl ( & final_dir, & image_data, & image_ref) . await ;
62+ let result = Self :: store_image_impl ( & final_dir, image_data, & image_ref) . await ;
6063 let _ = responder. send ( result) ;
6164 }
6265 FileCommand :: DeleteImage {
@@ -78,14 +81,34 @@ impl FileStore {
7881
7982 async fn store_image_impl (
8083 final_dir : & Path ,
81- image_data : & [ u8 ] ,
84+ image_data : PulledImageData ,
8285 image_ref : & str ,
8386 ) -> Result < ( ) , std:: io:: Error > {
8487 fs:: create_dir_all ( final_dir) . await ?;
85- let final_disk_path = final_dir. join ( "disk.image" ) ;
86- let mut file = fs:: File :: create ( final_disk_path) . await ?;
87- file. write_all ( image_data) . await ?;
8888
89+ // Handle both single-blob rootfs (for VMs) and layered rootfs (for containers)
90+ if image_data. layers . len ( ) == 1
91+ && image_ref. contains ( "cloud-hypervisor" )
92+ {
93+ // Assuming this is a single rootfs blob for a VM
94+ let final_disk_path = final_dir. join ( "disk.image" ) ;
95+ fs:: write ( final_disk_path, & image_data. layers [ 0 ] ) . await ?;
96+ } else {
97+ // Unpack layers for a container
98+ let rootfs_path = final_dir. join ( "rootfs" ) ;
99+ fs:: create_dir_all ( & rootfs_path) . await ?;
100+ for layer_data in image_data. layers {
101+ let cursor = Cursor :: new ( layer_data) ;
102+ let decoder = GzDecoder :: new ( cursor) ;
103+ let mut archive = Archive :: new ( decoder) ;
104+ archive. unpack ( & rootfs_path) ?;
105+ }
106+ }
107+
108+ // Save OCI config.json
109+ fs:: write ( final_dir. join ( "config.json" ) , image_data. config ) . await ?;
110+
111+ // Save internal metadata
89112 let metadata = ImageMetadata {
90113 image_ref : image_ref. to_string ( ) ,
91114 } ;
@@ -114,8 +137,9 @@ impl FileStore {
114137 if let Some ( uuid) = path. file_name ( ) . and_then ( |s| s. to_str ( ) ) {
115138 let metadata_path = path. join ( "metadata.json" ) ;
116139 let disk_image_path = path. join ( "disk.image" ) ;
140+ let rootfs_path = path. join ( "rootfs" ) ;
117141
118- if metadata_path. exists ( ) && disk_image_path. exists ( ) {
142+ if metadata_path. exists ( ) && ( disk_image_path. exists ( ) || rootfs_path . exists ( ) ) {
119143 if let Ok ( content) = fs:: read_to_string ( & metadata_path) . await {
120144 if let Ok ( metadata) = serde_json:: from_str :: < ImageMetadata > ( & content) {
121145 let image_info = ImageInfo {
@@ -139,4 +163,4 @@ impl FileStore {
139163 ) ;
140164 store
141165 }
142- }
166+ }
0 commit comments