Skip to content

Commit 81f4434

Browse files
committed
Enhance image service to support container OCI images
Signed-off-by: Guvenc Gulce <[email protected]>
1 parent 3500a6f commit 81f4434

File tree

7 files changed

+340
-35
lines changed

7 files changed

+340
-35
lines changed

Cargo.lock

Lines changed: 147 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/image_commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct ImageArgs {
2121
long,
2222
global = true,
2323
env = "FEOS_IMAGE_SOCKET",
24-
default_value = "/tmp/image_service.sock"
24+
default_value = "/tmp/feos/image_service.sock"
2525
)]
2626
pub socket: PathBuf,
2727

feos/services/image-service/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ serde = { workspace = true }
1616
serde_json = { workspace = true }
1717
prost = { workspace = true }
1818
prost-types = { workspace = true }
19-
thiserror = { workspace = true }
19+
thiserror = { workspace = true }
20+
tar = "0.4"
21+
flate2 = "1.0"

feos/services/image-service/src/filestore.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
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};
55
use feos_proto::image_service::{ImageInfo, ImageState};
6+
use flate2::read::GzDecoder;
67
use log::{error, info, warn};
78
use serde::{Deserialize, Serialize};
89
use std::collections::HashMap;
10+
use std::io::Cursor;
911
use 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)]
1316
struct 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

Comments
 (0)