#![allow(dead_code)] use std::env; use std::path::PathBuf; pub use futures_util::{StreamExt, TryStreamExt}; pub use podman_api::{api, conn, models, opts, Podman}; pub use tempdir::TempDir; pub const DEFAULT_IMAGE: &str = "ubuntu:latest"; pub const DEFAULT_CMD: &str = "sleep inf"; pub const DEFAULT_CMD_ARRAY: &[&str] = &["sleep", "inf"]; pub const TEST_IMAGE_PATH: &str = "/var/test123"; const URI_ENV_VAR: &str = "PODMAN_API_URI"; pub fn init_runtime() -> Podman { let _ = env_logger::try_init(); if let Ok(uri) = env::var(URI_ENV_VAR) { Podman::new(uri).unwrap() } else { #[cfg(unix)] { let uid = nix::unistd::Uid::effective(); let podman_dir = PathBuf::from(format!("/run/user/{uid}/podman")); let podman_root_dir = PathBuf::from("/run/podman"); if podman_dir.exists() { Podman::unix(podman_dir.join("podman.sock")) } else if podman_root_dir.exists() { Podman::unix(podman_root_dir.join("podman.sock")) } else { panic!( "Podman socket not found. Tried {URI_ENV_VAR} env variable, {} and {}", podman_dir.display(), podman_root_dir.display() ); } } #[cfg(not(unix))] { panic!("Podman socket not found. Try setting the {URI_ENV_VAR} env variable",); } } } pub async fn create_base_container( podman: &Podman, name: &str, opts: Option, ) -> api::Container { cleanup_container(podman, name).await; let opts = opts.unwrap_or_else(|| { opts::ContainerCreateOpts::builder() .name(name) .image(DEFAULT_IMAGE) .command(DEFAULT_CMD_ARRAY) .build() }); podman .containers() .create(&opts) .await .expect("created base container"); podman.containers().get(name) } pub async fn cleanup_container(podman: &Podman, name: &str) { let _ = podman.containers().get(name).remove().await; } pub async fn get_container_full_id(podman: &Podman, name: &str) -> String { podman .containers() .get(name) .inspect() .await .map(|data| data.id) .expect("container inspect data") .expect("container full id") } pub fn tempdir_with_dockerfile(name: &str, content: Option<&str>) -> TempDir { let tmp = TempDir::new(name).expect("temp dir for image"); let default_dockerfile = format!( "FROM {DEFAULT_IMAGE}\nRUN echo 1234 > {TEST_IMAGE_PATH}\nRUN echo 321\nCMD sleep inf", ); std::fs::write( tmp.path().join("Dockerfile"), content.unwrap_or(default_dockerfile.as_str()), ) .expect("saved Dockerfile"); tmp } pub async fn create_base_image( podman: &Podman, tag: &str, opts: Option, ) -> api::Image { let images = podman.images(); let _ = images.get(tag).remove().await; let tmp = tempdir_with_dockerfile(tag, None); let opts = opts.unwrap_or_else(|| { opts::ImageBuildOpts::builder(tmp.path().to_string_lossy()) .tag(tag) .build() }); let mut image_stream = images.build(&opts).expect("image build stream"); let mut last = None; while let Some(chunk) = image_stream.next().await { assert!(chunk.is_ok()); last = Some(chunk); } podman .images() .get(last.unwrap().unwrap().stream.trim_end().to_string()) } pub async fn get_image_full_id(podman: &Podman, name: &str) -> String { podman .images() .get(name) .inspect() .await .map(|data| data.id) .expect("image inspect data") .expect("image full id") } pub async fn create_base_volume( podman: &Podman, name: &str, opts: Option, ) -> api::Volume { cleanup_volume(podman, name).await; let opts = opts.unwrap_or_else(|| opts::VolumeCreateOpts::builder().name(name).build()); podman .volumes() .create(&opts) .await .expect("created base volume"); podman.volumes().get(name) } pub async fn cleanup_volume(podman: &Podman, name: &str) { let _ = podman.volumes().get(name).remove().await; } pub async fn create_base_network( podman: &Podman, name: &str, opts: Option, ) -> api::Network { cleanup_network(podman, name).await; let opts = opts.unwrap_or_else(|| opts::NetworkCreateOpts::builder().name(name).build()); podman .networks() .create(&opts) .await .expect("created base network"); podman.networks().get(name) } pub async fn cleanup_network(podman: &Podman, name: &str) { let _ = podman.networks().get(name).remove().await; }