use std::time::Duration; use anyhow::{anyhow, Result}; use axum::extract::{Multipart, State}; use bollard::{ container::{ Config as ContainerConfig, CreateContainerOptions, StartContainerOptions, }, image::CreateImageOptions, Docker, }; use entity::service; use futures::{FutureExt, TryStreamExt}; use sea_orm::{ActiveModelTrait, Set}; use tokio::time::sleep; use crate::{ config::{Config, SourceConfig}, error::AppError, jobs::{Job, Schedule}, AppState, }; pub async fn handle_upload_configuration( state: State, form: Multipart, ) -> Result<(), AppError> { let upload_form = extract_multipart(form).await.unwrap(); let config_string = serde_json::to_string(&upload_form.config).unwrap(); state .tx .send(Job { code: async move { spawn_docker(&upload_form.config).await.unwrap(); println!("done with job"); } .boxed(), schedule: Schedule::ASAP, }) .unwrap(); println!("spawned job"); service::ActiveModel { name: Set(upload_form.name), config: Set(config_string), overall_status: Set("New".into()), ..Default::default() } .save(&state.conn) .await .unwrap(); Ok(()) } struct UploadForm { name: String, config: Config, } async fn extract_multipart(mut form: Multipart) -> Result { let mut name = None; let mut config = None::; while let Some(field) = form.next_field().await.unwrap() { let key = field.name().unwrap().to_owned(); let value = String::from_utf8(field.bytes().await.unwrap().to_vec()).unwrap(); match key.as_ref() { "name" => name = Some(value), "config" => config = Some(serde_yaml::from_str(&value).unwrap()), _ => return Err(anyhow!("error").into()), } } Ok(UploadForm { name: name.unwrap(), config: config.unwrap(), }) } async fn spawn_docker(config: &Config) -> Result<()> { println!("Loading config: {config:?}"); let docker = Docker::connect_with_local_defaults().unwrap(); println!("connected to docker {docker:?}"); sleep(Duration::from_secs(1)).await; for (service_name, service_config) in config.service.iter() { println!("preparing config for {}", service_name); let SourceConfig::Image { image: from_image } = &service_config.source; println!("creating image {}", from_image); let mut result_stream = docker.create_image( Some(CreateImageOptions { from_image: from_image.to_owned(), ..Default::default() }), None, None, ); println!("result stream: "); while let Ok(Some(v)) = result_stream.try_next().await { println!("v: {v:?}"); } println!("completed pulling."); // create a container let result = docker .create_container( Some(CreateContainerOptions:: { ..Default::default() }), ContainerConfig { image: Some(from_image.to_owned()), ..Default::default() }, ) .await .unwrap(); docker .start_container(&result.id, None::>) .await .unwrap(); println!("result: {result:?}"); } Ok(()) }