diff --git a/rhai_tests/nerdctl/01_container_operations.rhai b/rhai_tests/nerdctl/01_container_operations.rhai index ab14ef2..5ae03be 100644 --- a/rhai_tests/nerdctl/01_container_operations.rhai +++ b/rhai_tests/nerdctl/01_container_operations.rhai @@ -167,9 +167,14 @@ try { container.detach = true; assert_eq(container.detach, true, "Container detach should be true"); - // TODO: Test health_check setter and getter + // Test health_check setter and getter print("Testing health_check setter and getter..."); - + let health_check_new = health_check_new("example_cmd"); + container.health_check = health_check_new; + container.health_check.interval = "example_interval"; + assert_eq(container.health_check.cmd, "example_cmd", "Container health check cmd should match"); + assert_eq(container.health_check.interval, "example_interval", "Container health check interval should match"); + // Test snapshotter setter and getter print("Testing snapshotter setter and getter..."); container.snapshotter = "stargz"; diff --git a/virt/src/buildah/builder.rs b/virt/src/buildah/builder.rs index 5a4ea22..8720bf3 100644 --- a/virt/src/buildah/builder.rs +++ b/virt/src/buildah/builder.rs @@ -2,7 +2,6 @@ use crate::buildah::{ execute_buildah_command, set_thread_local_debug, thread_local_debug, BuildahError, Image, }; use sal_process::CommandResult; -use std::collections::HashMap; /// Builder struct for buildah operations #[derive(Clone)] diff --git a/virt/src/nerdctl/container_types.rs b/virt/src/nerdctl/container_types.rs index a78b559..051ab98 100644 --- a/virt/src/nerdctl/container_types.rs +++ b/virt/src/nerdctl/container_types.rs @@ -42,7 +42,7 @@ pub struct Container { } /// Health check configuration for a container -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct HealthCheck { /// Command to run for health check pub cmd: String, diff --git a/virt/src/rhai/buildah.rs b/virt/src/rhai/buildah.rs index fad2b70..5e18432 100644 --- a/virt/src/rhai/buildah.rs +++ b/virt/src/rhai/buildah.rs @@ -3,9 +3,8 @@ //! This module provides Rhai wrappers for the functions in the Buildah module. use crate::buildah::{BuildahError, Builder, ContentOperations, Image}; -use rhai::{Array, Dynamic, Engine, EvalAltResult, Map}; +use rhai::{Array, Dynamic, Engine, EvalAltResult}; use sal_process::CommandResult; -use std::collections::HashMap; /// Register Buildah module functions with the Rhai engine /// @@ -45,7 +44,6 @@ pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box engine.register_fn("image_push", builder_image_push); engine.register_fn("image_tag", builder_image_tag); engine.register_fn("build", builder_build); - engine.register_fn("read_content", builder_read_content); Ok(()) } @@ -89,13 +87,13 @@ fn register_bah_types(engine: &mut Engine) -> Result<(), Box> { } // Helper functions for error conversion -fn bah_error_to_rhai_error(result: Result) -> Result> { - result.map_err(|e| { +impl From for Box { + fn from(err: BuildahError) -> Self { Box::new(EvalAltResult::ErrorRuntime( - format!("Buildah error: {}", e).into(), + format!("Buildah error: {}", err).into(), rhai::Position::NONE, )) - }) + } } // Helper function to convert Rhai Array of pairs to a Vec of tuples @@ -141,7 +139,7 @@ fn convert_array_to_vec( /// Create a new Builder pub fn bah_new(name: &str, image: &str) -> Result> { - bah_error_to_rhai_error(Builder::new(name, image)) + Builder::new(name, image).map_err(Into::into) } // Builder instance methods @@ -149,7 +147,7 @@ pub fn builder_run( builder: &mut Builder, command: &str, ) -> Result> { - bah_error_to_rhai_error(builder.run(command)) + builder.run(command).map_err(Into::into) } pub fn builder_run_with_isolation( @@ -157,7 +155,9 @@ pub fn builder_run_with_isolation( command: &str, isolation: &str, ) -> Result> { - bah_error_to_rhai_error(builder.run_with_isolation(command, isolation)) + builder + .run_with_isolation(command, isolation) + .map_err(Into::into) } pub fn builder_copy( @@ -165,7 +165,7 @@ pub fn builder_copy( source: &str, dest: &str, ) -> Result> { - bah_error_to_rhai_error(builder.copy(source, dest)) + builder.copy(source, dest).map_err(Into::into) } pub fn builder_add( @@ -173,7 +173,7 @@ pub fn builder_add( source: &str, dest: &str, ) -> Result> { - bah_error_to_rhai_error(builder.add(source, dest)) + builder.add(source, dest).map_err(Into::into) } pub fn builder_commit( @@ -182,11 +182,13 @@ pub fn builder_commit( options: Array, ) -> Result> { let commit_options = convert_array_to_vec(options)?; - bah_error_to_rhai_error(builder.commit(image_name, Some(commit_options))) + builder + .commit(image_name, Some(commit_options)) + .map_err(Into::into) } pub fn builder_remove(builder: &mut Builder) -> Result> { - bah_error_to_rhai_error(builder.remove()) + builder.remove().map_err(Into::into) } pub fn builder_config( @@ -194,7 +196,7 @@ pub fn builder_config( options: Array, ) -> Result> { let config_options = convert_array_to_vec(options)?; - bah_error_to_rhai_error(builder.config(config_options)) + builder.config(config_options).map_err(Into::into) } /// Set the entrypoint for the container @@ -206,7 +208,7 @@ pub fn builder_set_entrypoint( .into_iter() .map(|item| item.into_string().unwrap_or_default()) .collect(); - bah_error_to_rhai_error(builder.set_entrypoint(entrypoint_vec)) + builder.set_entrypoint(entrypoint_vec).map_err(Into::into) } /// Set the default command for the container @@ -218,7 +220,7 @@ pub fn builder_set_cmd( .into_iter() .map(|item| item.into_string().unwrap_or_default()) .collect(); - bah_error_to_rhai_error(builder.set_cmd(cmd_vec)) + builder.set_cmd(cmd_vec).map_err(Into::into) } /// Write content to a file in the container @@ -228,11 +230,7 @@ pub fn builder_write_content( dest_path: &str, ) -> Result> { if let Some(container_id) = builder.container_id() { - bah_error_to_rhai_error(ContentOperations::write_content( - container_id, - content, - dest_path, - )) + ContentOperations::write_content(container_id, content, dest_path).map_err(Into::into) } else { Err(Box::new(EvalAltResult::ErrorRuntime( "No container ID available".into(), @@ -247,7 +245,7 @@ pub fn builder_read_content( source_path: &str, ) -> Result> { if let Some(container_id) = builder.container_id() { - bah_error_to_rhai_error(ContentOperations::read_content(container_id, source_path)) + ContentOperations::read_content(container_id, source_path).map_err(Into::into) } else { Err(Box::new(EvalAltResult::ErrorRuntime( "No container ID available".into(), @@ -258,7 +256,7 @@ pub fn builder_read_content( // Builder static methods pub fn builder_images(_builder: &mut Builder) -> Result> { - let images = bah_error_to_rhai_error(Builder::images())?; + let images = Builder::images()?; // Convert Vec to Rhai Array let mut array = Array::new(); @@ -273,7 +271,7 @@ pub fn builder_image_remove( _builder: &mut Builder, image: &str, ) -> Result> { - bah_error_to_rhai_error(Builder::image_remove(image)) + Builder::image_remove(image).map_err(Into::into) } pub fn builder_image_pull( @@ -281,7 +279,7 @@ pub fn builder_image_pull( image: &str, tls_verify: bool, ) -> Result> { - bah_error_to_rhai_error(Builder::image_pull(image, tls_verify)) + Builder::image_pull(image, tls_verify).map_err(Into::into) } pub fn builder_image_push( @@ -290,7 +288,7 @@ pub fn builder_image_push( destination: &str, tls_verify: bool, ) -> Result> { - bah_error_to_rhai_error(Builder::image_push(image, destination, tls_verify)) + Builder::image_push(image, destination, tls_verify).map_err(Into::into) } pub fn builder_image_tag( @@ -298,7 +296,7 @@ pub fn builder_image_tag( image: &str, new_name: &str, ) -> Result> { - bah_error_to_rhai_error(Builder::image_tag(image, new_name)) + Builder::image_tag(image, new_name).map_err(Into::into) } // Getter functions for Builder properties @@ -329,7 +327,7 @@ pub fn set_builder_debug(builder: &mut Builder, debug: bool) { // Reset function for Builder pub fn builder_reset(builder: &mut Builder) -> Result<(), Box> { - bah_error_to_rhai_error(builder.reset()) + builder.reset().map_err(Into::into) } // Build function for Builder @@ -340,10 +338,5 @@ pub fn builder_build( file: &str, isolation: &str, ) -> Result> { - bah_error_to_rhai_error(Builder::build( - Some(tag), - context_dir, - file, - Some(isolation), - )) + Builder::build(Some(tag), context_dir, file, Some(isolation)).map_err(Into::into) } diff --git a/virt/src/rhai/nerdctl.rs b/virt/src/rhai/nerdctl.rs index 78f6f3c..496e5ba 100644 --- a/virt/src/rhai/nerdctl.rs +++ b/virt/src/rhai/nerdctl.rs @@ -7,33 +7,32 @@ use rhai::{Array, Dynamic, Engine, EvalAltResult, Map}; use sal_process::CommandResult; // Helper functions for error conversion with improved context -fn nerdctl_error_to_rhai_error( - result: Result, -) -> Result> { - result.map_err(|e| { - // Create a more detailed error message based on the error type - let error_message = match &e { - NerdctlError::CommandExecutionFailed(io_err) => { - format!("Failed to execute nerdctl command: {}. This may indicate nerdctl is not installed or not in PATH.", io_err) - }, - NerdctlError::CommandFailed(msg) => { - format!("Nerdctl command failed: {}. Check container status and logs for more details.", msg) - }, - NerdctlError::JsonParseError(msg) => { - format!("Failed to parse nerdctl JSON output: {}. This may indicate an incompatible nerdctl version.", msg) - }, - NerdctlError::ConversionError(msg) => { - format!("Data conversion error: {}. This may indicate unexpected output format from nerdctl.", msg) - }, - NerdctlError::Other(msg) => { - format!("Nerdctl error: {}. This is an unexpected error.", msg) - }, +impl From for Box { + fn from(err: NerdctlError) -> Self { + let error_message = match err { + NerdctlError::CommandExecutionFailed(io_err) => format!( + "Failed to execute nerdctl command: {}. This may indicate nerdctl is not installed or not in PATH.", + io_err + ), + NerdctlError::CommandFailed(msg) => format!( + "Nerdctl command failed: {}. Check container status and logs for more details.", + msg + ), + NerdctlError::JsonParseError(msg) => format!( + "Failed to parse nerdctl JSON output: {}. This may indicate an incompatible nerdctl version.", + msg + ), + NerdctlError::ConversionError(msg) => format!( + "Data conversion error: {}. This may indicate unexpected output format from nerdctl.", + msg + ), + NerdctlError::Other(msg) => format!("Nerdctl error: {}. This is an unexpected error.", msg), }; Box::new(EvalAltResult::ErrorRuntime( error_message.into(), - rhai::Position::NONE + rhai::Position::NONE, )) - }) + } } // @@ -42,12 +41,7 @@ fn nerdctl_error_to_rhai_error( /// Create a new Container pub fn container_new(name: &str) -> Result> { - nerdctl_error_to_rhai_error(Container::new(name)) -} - -/// Create a Container from an image -pub fn container_from_image(name: &str, image: &str) -> Result> { - nerdctl_error_to_rhai_error(Container::from_image(name, image)) + Container::new(name).map_err(Into::into) } /// Reset the container configuration to defaults while keeping the name and image @@ -55,19 +49,10 @@ pub fn container_reset(container: Container) -> Container { container.reset() } -// TODO: remove? -/// Set health check with options for a Container -pub fn container_with_health_check_options( - container: Container, - cmd: &str, - interval: Option<&str>, - timeout: Option<&str>, - retries: Option, - start_period: Option<&str>, -) -> Container { - // Convert i64 to u32 for retries - let retries_u32 = retries.map(|r| r as u32); - container.with_health_check_options(cmd, interval, timeout, retries_u32, start_period) +pub fn health_check_new(cmd: &str) -> Result> { + let health_check = HealthCheck::new(cmd); + + Ok(health_check) } /// Build and run the Container @@ -134,7 +119,7 @@ pub fn container_build(container: Container) -> Result err, }; - nerdctl_error_to_rhai_error(Err(enhanced_error)) + Err(enhanced_error.into()) } } } @@ -191,19 +176,19 @@ pub fn container_start(container: &mut Container) -> Result err, }; - nerdctl_error_to_rhai_error(Err(enhanced_error)) + Err(enhanced_error.into()) } } } /// Stop the Container pub fn container_stop(container: &mut Container) -> Result> { - nerdctl_error_to_rhai_error(container.stop()) + container.stop().map_err(Into::into) } /// Remove the Container pub fn container_remove(container: &mut Container) -> Result> { - nerdctl_error_to_rhai_error(container.remove()) + container.remove().map_err(Into::into) } /// Execute a command in the Container @@ -211,7 +196,7 @@ pub fn container_exec( container: &mut Container, command: &str, ) -> Result> { - nerdctl_error_to_rhai_error(container.exec(command)) + container.exec(command).map_err(Into::into) } /// Get container logs @@ -235,7 +220,7 @@ pub fn container_logs(container: &mut Container) -> Result Result> { - nerdctl_error_to_rhai_error(container.copy(source, dest)) + container.copy(source, dest).map_err(Into::into) } /// Create a new Map with default run options @@ -267,12 +252,12 @@ pub fn new_run_options() -> Map { /// /// Run a container from an image. pub fn nerdctl_run(image: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::run(image, None, true, None, None)) + nerdctl::run(image, None, true, None, None).map_err(Into::into) } /// Run a container with a name pub fn nerdctl_run_with_name(image: &str, name: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::run(image, Some(name), true, None, None)) + nerdctl::run(image, Some(name), true, None, None).map_err(Into::into) } /// Run a container with a port mapping @@ -282,49 +267,49 @@ pub fn nerdctl_run_with_port( port: &str, ) -> Result> { let ports = vec![port]; - nerdctl_error_to_rhai_error(nerdctl::run(image, Some(name), true, Some(&ports), None)) + nerdctl::run(image, Some(name), true, Some(&ports), None).map_err(Into::into) } /// Wrapper for nerdctl::exec /// /// Execute a command in a container. pub fn nerdctl_exec(container: &str, command: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::exec(container, command)) + nerdctl::exec(container, command).map_err(Into::into) } /// Wrapper for nerdctl::copy /// /// Copy files between container and local filesystem. pub fn nerdctl_copy(source: &str, dest: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::copy(source, dest)) + nerdctl::copy(source, dest).map_err(Into::into) } /// Wrapper for nerdctl::stop /// /// Stop a container. pub fn nerdctl_stop(container: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::stop(container)) + nerdctl::stop(container).map_err(Into::into) } /// Wrapper for nerdctl::remove /// /// Remove a container. pub fn nerdctl_remove(container: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::remove(container)) + nerdctl::remove(container).map_err(Into::into) } /// Wrapper for nerdctl::list /// /// List containers. pub fn nerdctl_list(all: bool) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::list(all)) + nerdctl::list(all).map_err(Into::into) } /// Wrapper for nerdctl::logs /// /// Get container logs. pub fn nerdctl_logs(container: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::logs(container)) + nerdctl::logs(container).map_err(Into::into) } // @@ -335,14 +320,14 @@ pub fn nerdctl_logs(container: &str) -> Result /// /// List images in local storage. pub fn nerdctl_images() -> Result> { - nerdctl_error_to_rhai_error(nerdctl::images()) + nerdctl::images().map_err(Into::into) } /// Wrapper for nerdctl::image_remove /// /// Remove one or more images. pub fn nerdctl_image_remove(image: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_remove(image)) + nerdctl::image_remove(image).map_err(Into::into) } /// Wrapper for nerdctl::image_push @@ -352,21 +337,21 @@ pub fn nerdctl_image_push( image: &str, destination: &str, ) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_push(image, destination)) + nerdctl::image_push(image, destination).map_err(Into::into) } /// Wrapper for nerdctl::image_tag /// /// Add an additional name to a local image. pub fn nerdctl_image_tag(image: &str, new_name: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_tag(image, new_name)) + nerdctl::image_tag(image, new_name).map_err(Into::into) } /// Wrapper for nerdctl::image_pull /// /// Pull an image from a registry. pub fn nerdctl_image_pull(image: &str) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_pull(image)) + nerdctl::image_pull(image).map_err(Into::into) } /// Wrapper for nerdctl::image_commit @@ -376,7 +361,7 @@ pub fn nerdctl_image_commit( container: &str, image_name: &str, ) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_commit(container, image_name)) + nerdctl::image_commit(container, image_name).map_err(Into::into) } /// Wrapper for nerdctl::image_build @@ -386,7 +371,7 @@ pub fn nerdctl_image_build( tag: &str, context_path: &str, ) -> Result> { - nerdctl_error_to_rhai_error(nerdctl::image_build(tag, context_path)) + nerdctl::image_build(tag, context_path).map_err(Into::into) } /// Register Nerdctl module functions with the Rhai engine @@ -404,36 +389,13 @@ pub fn register_nerdctl_module(engine: &mut Engine) -> Result<(), Box Result<(), Box Result<(), Box> { + // Register Container type engine.register_type_with_name::("NerdctlContainer"); - engine.register_type_with_name::("NerdctlHealthCheck"); - - // Register getters & setters for HealthCheck properties - engine.register_get("cmd", |hc: &mut HealthCheck| hc.cmd.clone()); - engine.register_set("cmd", |hc: &mut HealthCheck, cmd: &str| { - hc.cmd = cmd.to_string(); - }); - engine.register_get("interval", |hc: &mut HealthCheck| { - hc.interval.clone().unwrap_or_default() - }); - engine.register_set("interval", |hc: &mut HealthCheck, interval: &str| { - hc.interval = Some(interval.to_string()); - }); - engine.register_get("timeout", |hc: &mut HealthCheck| { - hc.timeout.clone().unwrap_or_default() - }); - engine.register_set("timeout", |hc: &mut HealthCheck, timeout: &str| { - hc.timeout = Some(timeout.to_string()); - }); - engine.register_get("retries", |hc: &mut HealthCheck| { - hc.retries.map_or(0, |r| r as i64) - }); - engine.register_set("retries", |hc: &mut HealthCheck, retries: i64| { - hc.retries = Some(retries as u32); - }); - engine.register_get("start_period", |hc: &mut HealthCheck| { - hc.start_period.clone().unwrap_or_default() - }); - engine.register_set("start_period", |hc: &mut HealthCheck, start_period: &str| { - hc.start_period = Some(start_period.to_string()); - }); // Register getters & setters for Container properties - // -- name engine.register_get("name", |container: &mut Container| container.name.clone()); engine.register_set("image", |container: &mut Container, image: &str| { @@ -665,17 +596,50 @@ fn register_nerdctl_types(engine: &mut Engine) -> Result<(), Box> }, ); - // TODO: setters and getters for health_check // -- health_check - // engine.register_get("health_check", |container: &mut Container| { - // container.health_check.clone() - // }); - // engine.register_set( - // "health_check", - // |container: &mut Container, health_check: HealthCheck| { - // container.health_check = Some(health_check); - // }, - // ); + engine.register_type_with_name::("NerdctlHealthCheck"); + engine.register_get("health_check", |container: &mut Container| { + if let Some(health_check) = container.health_check.clone() { + Dynamic::from(health_check) + } else { + Dynamic::UNIT + } + }); + engine.register_set( + "health_check", + |container: &mut Container, health_check: HealthCheck| { + container.health_check = Some(health_check); + }, + ); + // Register getters & setters for HealthCheck properties + engine.register_get("cmd", |hc: &mut HealthCheck| hc.cmd.clone()); + engine.register_set("cmd", |hc: &mut HealthCheck, cmd: &str| { + hc.cmd = cmd.to_string(); + }); + engine.register_get("interval", |hc: &mut HealthCheck| { + hc.interval.clone().unwrap_or_default() + }); + engine.register_set("interval", |hc: &mut HealthCheck, interval: &str| { + hc.interval = Some(interval.to_string()); + }); + engine.register_get("timeout", |hc: &mut HealthCheck| { + hc.timeout.clone().unwrap_or_default() + }); + engine.register_set("timeout", |hc: &mut HealthCheck, timeout: &str| { + hc.timeout = Some(timeout.to_string()); + }); + engine.register_get("retries", |hc: &mut HealthCheck| { + hc.retries.map_or(0, |r| r as i64) + }); + engine.register_set("retries", |hc: &mut HealthCheck, retries: i64| { + hc.retries = Some(retries as u32); + }); + engine.register_get("start_period", |hc: &mut HealthCheck| { + hc.start_period.clone().unwrap_or_default() + }); + engine.register_set("start_period", |hc: &mut HealthCheck, start_period: &str| { + hc.start_period = Some(start_period.to_string()); + }); // -- detach engine.register_get("detach", |container: &mut Container| container.detach); @@ -693,7 +657,6 @@ fn register_nerdctl_types(engine: &mut Engine) -> Result<(), Box> // Register Image type and methods engine.register_type_with_name::("NerdctlImage"); - // Register getters for Image properties engine.register_get("id", |img: &mut Image| img.id.clone()); engine.register_get("repository", |img: &mut Image| img.repository.clone());