...
This commit is contained in:
@@ -7,11 +7,30 @@ use std::collections::HashMap;
|
||||
use crate::virt::nerdctl::{self, NerdctlError, Image, Container};
|
||||
use crate::process::CommandResult;
|
||||
|
||||
// Helper functions for error conversion
|
||||
// Helper functions for error conversion with improved context
|
||||
fn nerdctl_error_to_rhai_error<T>(result: Result<T, NerdctlError>) -> Result<T, Box<EvalAltResult>> {
|
||||
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)..
|
||||
},
|
||||
};
|
||||
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Nerdctl error: {}", e).into(),
|
||||
error_message.into(),
|
||||
rhai::Position::NONE
|
||||
))
|
||||
})
|
||||
@@ -86,9 +105,56 @@ pub fn container_build(container: Container) -> Result<Container, Box<EvalAltRes
|
||||
nerdctl_error_to_rhai_error(container.build())
|
||||
}
|
||||
|
||||
/// Start the Container
|
||||
/// Start the Container and verify it's running
|
||||
///
|
||||
/// This function starts the container and verifies that it's actually running.
|
||||
/// It returns detailed error information if the container fails to start or
|
||||
/// if it starts but stops immediately.
|
||||
pub fn container_start(container: &mut Container) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
nerdctl_error_to_rhai_error(container.start())
|
||||
// Get container details for better error reporting
|
||||
let container_name = container.name.clone();
|
||||
let container_id = container.container_id.clone().unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
// Try to start the container
|
||||
let start_result = container.start();
|
||||
|
||||
// Handle the result with improved error context
|
||||
match start_result {
|
||||
Ok(result) => {
|
||||
// Container started successfully
|
||||
Ok(result)
|
||||
},
|
||||
Err(err) => {
|
||||
// Add more context to the error
|
||||
let enhanced_error = match err {
|
||||
NerdctlError::CommandFailed(msg) => {
|
||||
// Check if this is a "container already running" error, which is not really an error
|
||||
if msg.contains("already running") {
|
||||
return Ok(CommandResult {
|
||||
stdout: format!("Container {} is already running", container_name),
|
||||
stderr: "".to_string(),
|
||||
success: true,
|
||||
code: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// Try to get more information about why the container might have failed to start
|
||||
let mut enhanced_msg = format!("Failed to start container '{}' (ID: {}): {}",
|
||||
container_name, container_id, msg);
|
||||
|
||||
// Try to check if the image exists
|
||||
if let Some(image) = &container.image {
|
||||
enhanced_msg.push_str(&format!("\nContainer was using image: {}", image));
|
||||
}
|
||||
|
||||
NerdctlError::CommandFailed(enhanced_msg)
|
||||
},
|
||||
_ => err
|
||||
};
|
||||
|
||||
nerdctl_error_to_rhai_error(Err(enhanced_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop the Container
|
||||
|
@@ -6,14 +6,76 @@ use super::container_types::{Container, ContainerStatus, ResourceUsage};
|
||||
use serde_json;
|
||||
|
||||
impl Container {
|
||||
/// Start the container
|
||||
/// Start the container and verify it's running
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<CommandResult, NerdctlError>` - Command result or error
|
||||
/// * `Result<CommandResult, NerdctlError>` - Command result or error with detailed information
|
||||
pub fn start(&self) -> Result<CommandResult, NerdctlError> {
|
||||
if let Some(container_id) = &self.container_id {
|
||||
execute_nerdctl_command(&["start", container_id])
|
||||
// First, try to start the container
|
||||
let start_result = execute_nerdctl_command(&["start", container_id]);
|
||||
|
||||
// If the start command failed, return the error with details
|
||||
if let Err(err) = &start_result {
|
||||
return Err(NerdctlError::CommandFailed(
|
||||
format!("Failed to start container {}: {}", container_id, err)
|
||||
));
|
||||
}
|
||||
|
||||
// Verify the container is actually running
|
||||
match self.verify_running() {
|
||||
Ok(true) => start_result,
|
||||
Ok(false) => {
|
||||
// Container started but isn't running - try to get more details
|
||||
if let Ok(status) = self.status() {
|
||||
Err(NerdctlError::CommandFailed(
|
||||
format!("Container {} started but is not running. Status: {}, State: {}, Health: {}",
|
||||
container_id,
|
||||
status.status,
|
||||
status.state,
|
||||
status.health_status.unwrap_or_else(|| "N/A".to_string())
|
||||
)
|
||||
))
|
||||
} else {
|
||||
Err(NerdctlError::CommandFailed(
|
||||
format!("Container {} started but is not running. Unable to get status details.",
|
||||
container_id
|
||||
)
|
||||
))
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
// Failed to verify if container is running
|
||||
Err(NerdctlError::CommandFailed(
|
||||
format!("Container {} may have started, but verification failed: {}",
|
||||
container_id, err
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(NerdctlError::Other("No container ID available".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify if the container is running
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, NerdctlError>` - True if running, false if not running, error if verification failed
|
||||
fn verify_running(&self) -> Result<bool, NerdctlError> {
|
||||
if let Some(container_id) = &self.container_id {
|
||||
// Use inspect to check if the container is running
|
||||
let inspect_result = execute_nerdctl_command(&["inspect", "--format", "{{.State.Running}}", container_id]);
|
||||
|
||||
match inspect_result {
|
||||
Ok(result) => {
|
||||
let running = result.stdout.trim().to_lowercase() == "true";
|
||||
Ok(running)
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
}
|
||||
} else {
|
||||
Err(NerdctlError::Other("No container ID available".to_string()))
|
||||
}
|
||||
|
Reference in New Issue
Block a user