Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support conversion progress #68

Merged
merged 18 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docker2fl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ toml = "0.4.2"
clap = { version = "4.2", features = ["derive"] }
serde = { version = "1.0.159" , features = ["derive"] }
tokio-async-drop = "0.1.0"
walkdir = "2.5.0"
132 changes: 90 additions & 42 deletions docker2fl/src/docker2fl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use bollard::container::{
};
use bollard::image::{CreateImageOptions, RemoveImageOptions};
use bollard::Docker;
use std::sync::mpsc::Sender;
use tempdir::TempDir;
use walkdir::WalkDir;

use anyhow::{Context, Result};
use futures_util::stream::StreamExt;
Expand All @@ -18,8 +21,6 @@ use tokio_async_drop::tokio_async_drop;
use rfs::fungi::Writer;
use rfs::store::Store;

use uuid::Uuid;

struct DockerInfo {
image_name: String,
container_name: String,
Expand All @@ -43,46 +44,87 @@ impl Drop for DockerInfo {
}
}

pub async fn convert<S: Store>(
pub struct DockerImageToFlist {
meta: Writer,
store: S,
image_name: &str,
image_name: String,
credentials: Option<DockerCredentials>,
) -> Result<()> {
#[cfg(unix)]
let docker = Docker::connect_with_socket_defaults().context("failed to create docker")?;
docker_tmp_dir: TempDir,
}

let container_name = Uuid::new_v4().to_string();
impl DockerImageToFlist {
pub fn new(
meta: Writer,
image_name: String,
credentials: Option<DockerCredentials>,
docker_tmp_dir: TempDir,
) -> Self {
DockerImageToFlist {
meta,
image_name,
credentials,
docker_tmp_dir,
}
}

let docker_tmp_dir = tempdir::TempDir::new(&container_name)?;
let docker_tmp_dir_path = docker_tmp_dir.path();
pub fn files_count(&self) -> usize {
WalkDir::new(self.docker_tmp_dir.path()).into_iter().count()
}

let docker_info = DockerInfo {
image_name: image_name.to_owned(),
container_name,
docker,
};
pub async fn prepare(&mut self) -> Result<()> {
rawdaGastan marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(unix)]
let docker = Docker::connect_with_socket_defaults().context("failed to create docker")?;

extract_image(
&docker_info.docker,
&docker_info.image_name,
&docker_info.container_name,
docker_tmp_dir_path,
credentials,
)
.await
.context("failed to extract docker image to a directory")?;
log::info!(
"docker image '{}' is extracted successfully",
docker_info.image_name
);
let container_file =
Path::file_stem(self.docker_tmp_dir.path()).expect("failed to get directory name");
let container_name = container_file
.to_str()
.expect("failed to get container name")
.to_owned();

let docker_info = DockerInfo {
image_name: self.image_name.to_owned(),
container_name,
docker,
};

extract_image(
&docker_info.docker,
&docker_info.image_name,
&docker_info.container_name,
self.docker_tmp_dir.path(),
self.credentials.clone(),
)
.await
.context("failed to extract docker image to a directory")?;
log::info!(
"docker image '{}' is extracted successfully",
docker_info.image_name
);

Ok(())
}

rfs::pack(meta, store, docker_tmp_dir_path, true)
pub async fn pack<S: Store>(&mut self, store: S, sender: Option<Sender<u32>>) -> Result<()> {
rawdaGastan marked this conversation as resolved.
Show resolved Hide resolved
rfs::pack(
self.meta.clone(),
store,
&self.docker_tmp_dir.path(),
true,
sender,
)
.await
.context("failed to pack flist")?;

log::info!("flist has been created successfully");
Ok(())
log::info!("flist has been created successfully");
Ok(())
}

pub async fn convert<S: Store>(&mut self, store: S, sender: Option<Sender<u32>>) -> Result<()> {
self.prepare().await?;
self.pack(store, sender).await?;

Ok(())
}
}

async fn extract_image(
Expand Down Expand Up @@ -202,35 +244,41 @@ async fn container_boot(
let mut env: HashMap<String, String> = HashMap::new();
let mut cwd = String::from("/");

let cmd = container_config.cmd.unwrap();
let cmd = container_config.cmd.expect("failed to get cmd configs");

if container_config.entrypoint.is_some() {
let entrypoint = container_config.entrypoint.unwrap();
command = (entrypoint.first().unwrap()).to_string();
let entrypoint = container_config
.entrypoint
.expect("failed to get entry point");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this should cause the entire process to panic? What if the container I am using is not configured with an entrypoint.

I really think all expect and unwrap here should instead return a suitable errors that can be handled instead of panicing

command = (entrypoint.first().expect("failed to get first entry point")).to_string();

if entrypoint.len() > 1 {
let (_, entries) = entrypoint.split_first().unwrap();
let (_, entries) = entrypoint
.split_first()
.expect("failed to split entry point");
args = entries.to_vec();
} else {
args = cmd;
}
} else {
command = (cmd.first().unwrap()).to_string();
let (_, entries) = cmd.split_first().unwrap();
command = (cmd.first().expect("failed to get first cmd")).to_string();
let (_, entries) = cmd.split_first().expect("failed to split cmd");
args = entries.to_vec();
}

if container_config.env.is_some() {
for entry in container_config.env.unwrap().iter() {
for entry in container_config.env.expect("failed to get env").iter() {
let mut split = entry.split('=');
env.insert(
split.next().unwrap().to_string(),
split.next().unwrap().to_string(),
split.next().expect("failed to get env key").to_string(),
split.next().expect("failed to get env value").to_string(),
);
}
}

let working_dir = container_config.working_dir.unwrap();
let working_dir = container_config
.working_dir
.expect("failed to get working dir");
if !working_dir.is_empty() {
cwd = working_dir;
}
Expand Down
9 changes: 8 additions & 1 deletion docker2fl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use bollard::auth::DockerCredentials;
use clap::{ArgAction, Parser};
use rfs::fungi;
use rfs::store::parse_router;
use uuid::Uuid;

mod docker2fl;

Expand Down Expand Up @@ -87,7 +88,13 @@ async fn main() -> Result<()> {
let meta = fungi::Writer::new(&fl_name).await?;
let store = parse_router(&opts.store).await?;

let res = docker2fl::convert(meta, store, &docker_image, credentials).await;
let container_name = Uuid::new_v4().to_string();
let docker_tmp_dir =
tempdir::TempDir::new(&container_name).expect("failed to create tmp directory");

let mut docker_to_fl =
docker2fl::DockerImageToFlist::new(meta, docker_image, credentials, docker_tmp_dir);
let res = docker_to_fl.convert(store, None).await;

// remove the file created with the writer if fl creation failed
if res.is_err() {
Expand Down
1 change: 1 addition & 0 deletions fl-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ utoipa = { version = "4", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "7", features = ["axum"] }
thiserror = "1.0.63"
hostname-validator = "1.1.1"
walkdir = "2.5.0"
2 changes: 2 additions & 0 deletions fl-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
fs,
path::PathBuf,
sync::{Arc, Mutex},
};
use utoipa::ToSchema;
Expand All @@ -20,6 +21,7 @@ pub struct Job {
#[derive(ToSchema)]
pub struct AppState {
pub jobs_state: Mutex<HashMap<String, handlers::FlistState>>,
pub flists_progress: Mutex<HashMap<PathBuf, f32>>,
pub db: Arc<dyn DB>,
pub config: Config,
}
Expand Down
Loading
Loading