feat: working erofs backend

This commit is contained in:
Alex Zenla
2024-04-14 07:06:19 +00:00
parent 8df9b36e3d
commit 5aa33facdc
9 changed files with 136 additions and 88 deletions

View File

@ -5,6 +5,7 @@ use std::{
};
use anyhow::{anyhow, Result};
use krata::launchcfg::LaunchPackedFormat;
use krata::v1::{
common::{
guest_image_spec::Image, Guest, GuestErrorInfo, GuestExitInfo, GuestNetworkState,
@ -238,6 +239,7 @@ impl GuestReconciler {
let info = self
.runtime
.launch(GuestLaunchRequest {
format: LaunchPackedFormat::Squashfs,
uuid: Some(uuid),
name: if spec.name.is_empty() {
None

View File

@ -4,7 +4,7 @@ use futures::stream::TryStreamExt;
use ipnetwork::IpNetwork;
use krata::ethtool::EthtoolHandle;
use krata::idm::client::IdmClient;
use krata::launchcfg::{LaunchInfo, LaunchNetwork};
use krata::launchcfg::{LaunchInfo, LaunchNetwork, LaunchPackedFormat};
use libc::{sethostname, setsid, TIOCSCTTY};
use log::{trace, warn};
use nix::ioctl_write_int_bad;
@ -80,11 +80,13 @@ impl GuestInit {
let idm = IdmClient::open("/dev/hvc1")
.await
.map_err(|x| anyhow!("failed to open idm client: {}", x))?;
self.mount_squashfs_images().await?;
self.mount_config_image().await?;
let config = self.parse_image_config().await?;
let launch = self.parse_launch_config().await?;
self.mount_root_image(launch.root.format.clone()).await?;
self.mount_new_root().await?;
self.bind_new_root().await?;
@ -185,24 +187,41 @@ impl GuestInit {
Ok(())
}
async fn mount_squashfs_images(&mut self) -> Result<()> {
trace!("mounting squashfs images");
let image_mount_path = Path::new(IMAGE_MOUNT_PATH);
async fn mount_config_image(&mut self) -> Result<()> {
trace!("mounting config image");
let config_mount_path = Path::new(CONFIG_MOUNT_PATH);
self.mount_squashfs(Path::new(IMAGE_BLOCK_DEVICE_PATH), image_mount_path)
.await?;
self.mount_squashfs(Path::new(CONFIG_BLOCK_DEVICE_PATH), config_mount_path)
self.mount_image(
Path::new(CONFIG_BLOCK_DEVICE_PATH),
config_mount_path,
LaunchPackedFormat::Squashfs,
)
.await?;
Ok(())
}
async fn mount_root_image(&mut self, format: LaunchPackedFormat) -> Result<()> {
trace!("mounting root image");
let image_mount_path = Path::new(IMAGE_MOUNT_PATH);
self.mount_image(Path::new(IMAGE_BLOCK_DEVICE_PATH), image_mount_path, format)
.await?;
Ok(())
}
async fn mount_squashfs(&mut self, from: &Path, to: &Path) -> Result<()> {
trace!("mounting squashfs image {:?} to {:?}", from, to);
async fn mount_image(
&mut self,
from: &Path,
to: &Path,
format: LaunchPackedFormat,
) -> Result<()> {
trace!("mounting {:?} image {:?} to {:?}", format, from, to);
if !to.is_dir() {
fs::create_dir(to).await?;
}
Mount::builder()
.fstype(FilesystemType::Manual("squashfs"))
.fstype(FilesystemType::Manual(match format {
LaunchPackedFormat::Squashfs => "squashfs",
LaunchPackedFormat::Erofs => "erofs",
}))
.flags(MountFlags::RDONLY)
.mount(from, to)?;
Ok(())

View File

@ -2,24 +2,30 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum LaunchPackedFormat {
Squashfs,
Erofs,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchNetworkIpv4 {
pub address: String,
pub gateway: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchNetworkIpv6 {
pub address: String,
pub gateway: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchNetworkResolver {
pub nameservers: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchNetwork {
pub link: String,
pub ipv4: LaunchNetworkIpv4,
@ -27,8 +33,14 @@ pub struct LaunchNetwork {
pub resolver: LaunchNetworkResolver,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchRoot {
pub format: LaunchPackedFormat,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchInfo {
pub root: LaunchRoot,
pub hostname: Option<String>,
pub network: Option<LaunchNetwork>,
pub env: HashMap<String, String>,

View File

@ -48,7 +48,7 @@ async fn main() -> Result<()> {
println!(
"generated squashfs of {} to {}",
image,
info.image_squashfs.to_string_lossy()
info.image.to_string_lossy()
);
Ok(())
}

View File

@ -28,10 +28,10 @@ impl ImageCache {
config_path.push(format!("{}.config.json", digest));
Ok(
if fs_path.exists() && manifest_path.exists() && config_path.exists() {
let squashfs_metadata = fs::metadata(&fs_path).await?;
let image_metadata = fs::metadata(&fs_path).await?;
let manifest_metadata = fs::metadata(&manifest_path).await?;
let config_metadata = fs::metadata(&config_path).await?;
if squashfs_metadata.is_file()
if image_metadata.is_file()
&& manifest_metadata.is_file()
&& config_metadata.is_file()
{
@ -64,7 +64,7 @@ impl ImageCache {
fs_path.push(format!("{}.{}", digest, format.extension()));
manifest_path.push(format!("{}.manifest.json", digest));
config_path.push(format!("{}.config.json", digest));
fs::copy(&info.image_squashfs, &fs_path).await?;
fs::copy(&info.image, &fs_path).await?;
let manifest_text = serde_json::to_string_pretty(&info.manifest)?;
fs::write(&manifest_path, manifest_text).await?;
let config_text = serde_json::to_string_pretty(&info.config)?;

View File

@ -20,19 +20,19 @@ use uuid::Uuid;
pub const IMAGE_PACKER_VERSION: u64 = 2;
pub struct ImageInfo {
pub image_squashfs: PathBuf,
pub image: PathBuf,
pub manifest: ImageManifest,
pub config: ImageConfiguration,
}
impl ImageInfo {
pub fn new(
squashfs: PathBuf,
image: PathBuf,
manifest: ImageManifest,
config: ImageConfiguration,
) -> Result<ImageInfo> {
Ok(ImageInfo {
image_squashfs: squashfs,
image,
manifest,
config,
})
@ -76,8 +76,8 @@ impl OciImageCompiler<'_> {
layer_dir.push("layer");
fs::create_dir_all(&layer_dir).await?;
let mut squash_file = tmp_dir.clone();
squash_file.push("image.squashfs");
let mut packed_file = tmp_dir.clone();
packed_file.push("image.packed");
let _guard = scopeguard::guard(tmp_dir.to_path_buf(), |delete| {
tokio::task::spawn(async move {
@ -85,7 +85,7 @@ impl OciImageCompiler<'_> {
});
});
let info = self
.download_and_compile(id, image, &layer_dir, &image_dir, &squash_file, format)
.download_and_compile(id, image, &layer_dir, &image_dir, &packed_file, format)
.await?;
Ok(info)
}
@ -96,7 +96,7 @@ impl OciImageCompiler<'_> {
image: &ImageName,
layer_dir: &Path,
image_dir: &Path,
squash_file: &Path,
packed_file: &Path,
format: OciPackerFormat,
) -> Result<ImageInfo> {
let mut progress = OciProgress {
@ -191,23 +191,24 @@ impl OciImageCompiler<'_> {
}
}
let image_dir_squash = image_dir.to_path_buf();
let squash_file_squash = squash_file.to_path_buf();
let progress_squash = progress.clone();
let image_dir_pack = image_dir.to_path_buf();
let packed_file_pack = packed_file.to_path_buf();
let progress_pack = progress.clone();
let progress_context = self.progress.clone();
let format_pack = format;
progress = tokio::task::spawn_blocking(move || {
OciImageCompiler::pack(
OciPackerFormat::Squashfs,
&image_dir_squash,
&squash_file_squash,
progress_squash,
format_pack,
&image_dir_pack,
&packed_file_pack,
progress_pack,
progress_context,
)
})
.await??;
let info = ImageInfo::new(
squash_file.to_path_buf(),
packed_file.to_path_buf(),
local.image.manifest,
local.config,
)?;
@ -371,14 +372,13 @@ impl OciImageCompiler<'_> {
fn pack(
format: OciPackerFormat,
image_dir: &Path,
squash_file: &Path,
packed_file: &Path,
mut progress: OciProgress,
progress_context: OciProgressContext,
) -> Result<OciProgress> {
progress_context.update(&progress);
let backend = format.detect_best_backend();
let backend = backend.create();
backend.pack(&mut progress, &progress_context, image_dir, squash_file)?;
backend.pack(&mut progress, &progress_context, image_dir, packed_file)?;
std::fs::remove_dir_all(image_dir)?;
progress.phase = OciProgressPhase::Packing;
progress.value = progress.total;

View File

@ -8,6 +8,7 @@ use anyhow::{anyhow, Result};
use ipnetwork::{IpNetwork, Ipv4Network};
use krata::launchcfg::{
LaunchInfo, LaunchNetwork, LaunchNetworkIpv4, LaunchNetworkIpv6, LaunchNetworkResolver,
LaunchPackedFormat, LaunchRoot,
};
use krataoci::packer::OciPackerFormat;
use krataoci::progress::OciProgressContext;
@ -27,6 +28,7 @@ use krataoci::{
use super::{GuestInfo, GuestState};
pub struct GuestLaunchRequest<'a> {
pub format: LaunchPackedFormat,
pub uuid: Option<Uuid>,
pub name: Option<&'a str>,
pub image: &'a str,
@ -59,7 +61,10 @@ impl GuestLauncher {
request.image,
&context.image_cache,
&context.oci_progress_context,
OciPackerFormat::Squashfs,
match request.format {
LaunchPackedFormat::Squashfs => OciPackerFormat::Squashfs,
LaunchPackedFormat::Erofs => OciPackerFormat::Erofs,
},
)
.await?;
@ -79,6 +84,9 @@ impl GuestLauncher {
let ipv6_network_mask: u32 = 10;
let launch_config = LaunchInfo {
root: LaunchRoot {
format: request.format.clone(),
},
hostname: Some(
request
.name
@ -112,9 +120,9 @@ impl GuestLauncher {
cfgblk.build(&launch_config)?;
let image_squashfs_path = image_info
.image_squashfs
.image
.to_str()
.ok_or_else(|| anyhow!("failed to convert image squashfs path to string"))?;
.ok_or_else(|| anyhow!("failed to convert image path to string"))?;
let cfgblk_dir_path = cfgblk
.dir