From 7bf2ffe47d20111bdb24253f6c443f9b57355394 Mon Sep 17 00:00:00 2001 From: despiegk Date: Sat, 5 Apr 2025 15:10:02 +0200 Subject: [PATCH] ... --- src/docs/docs/sal/buildah.md | 117 ++++++++++- src/docs/docs/sal/nerdctl.md | 101 ++++++--- src/docs/docs/sal/os.md | 43 +++- src/os/download.rs | 292 ++++++++++++++++++++------ src/rhai/os.rs | 16 ++ src/rhaiexamples/buildah.rhai | 57 ++--- src/rhaiexamples/download_test.rhai | 39 +++- src/rhaiexamples/nerdctl_install.rhai | 28 ++- 8 files changed, 554 insertions(+), 139 deletions(-) diff --git a/src/docs/docs/sal/buildah.md b/src/docs/docs/sal/buildah.md index 23919a3..b2cce8f 100644 --- a/src/docs/docs/sal/buildah.md +++ b/src/docs/docs/sal/buildah.md @@ -25,7 +25,6 @@ let image = builder.image; ``` ### Builder Methods - The Builder object provides the following methods: - `run(command)`: Run a command in the container @@ -36,12 +35,18 @@ The Builder object provides the following methods: - `remove()`: Remove the container - `reset()`: Remove the container and clear the container_id - `config(options)`: Configure container metadata +- `set_entrypoint(entrypoint)`: Set the entrypoint for the container +- `set_cmd(cmd)`: Set the default command for the container +- `debug_mode`: Get or set the debug flag (true/false) +- `write_content(content, dest_path)`: Write content to a file in the container +- `read_content(source_path)`: Read content from a file in the container - `images()`: List images in local storage - `image_remove(image)`: Remove an image - `image_pull(image, tls_verify)`: Pull an image from a registry - `image_push(image, destination, tls_verify)`: Push an image to a registry - `image_tag(image, new_name)`: Add a tag to an image - `build(tag, context_dir, file, isolation)`: Build an image from a Dockerfile +- `build(tag, context_dir, file, isolation)`: Build an image from a Dockerfile ### Example @@ -49,6 +54,9 @@ The Builder object provides the following methods: // Create a builder let builder = bah_new("my-container", "alpine:latest"); +// Enable debug mode to see command output +builder.debug_mode = true; + // Reset the builder to remove any existing container builder.reset(); @@ -59,6 +67,16 @@ builder = bah_new("my-container", "alpine:latest"); let result = builder.run("echo 'Hello from container'"); println(`Command output: ${result.stdout}`); +// Write content directly to a file in the container +let script_content = `#!/bin/sh +echo "Hello from startup script" +`; +builder.write_content(script_content, "/start.sh"); +builder.run("chmod +x /start.sh"); + +// Set the entrypoint for the container +builder.set_entrypoint("/start.sh"); + // Add a file file_write("test_file.txt", "Test content"); builder.add("test_file.txt", "/"); @@ -122,3 +140,100 @@ builder.reset(); // Create a new container with the same name builder = bah_new("my-container", "alpine:latest"); ``` + +### `debug_mode` + +Get or set the debug flag for the Builder. When debug mode is enabled, all buildah commands will output their stdout/stderr, making it easier to debug issues. + +**Example:** +```js +// Create a Builder +let builder = bah_new("my-container", "alpine:latest"); + +// Enable debug mode +builder.debug_mode = true; + +// Run a command with debug output +builder.run("echo 'Hello with debug'"); + +// Disable debug mode +builder.debug_mode = false; +``` + +### `set_entrypoint(entrypoint)` + +Sets the entrypoint for the container. The entrypoint is the command that will be executed when the container starts. + +**Parameters:** +- `entrypoint` (string): The entrypoint command + +**Returns:** Command result if successful. + +**Example:** +```js +// Create a Builder +let builder = bah_new("my-container", "alpine:latest"); + +// Set the entrypoint +builder.set_entrypoint("/start.sh"); +``` + +### `set_cmd(cmd)` + +Sets the default command for the container. This is used as arguments to the entrypoint. + +**Parameters:** +- `cmd` (string): The default command + +**Returns:** Command result if successful. + +**Example:** +```js +// Create a Builder +let builder = bah_new("my-container", "alpine:latest"); + +// Set the default command +builder.set_cmd("--verbose"); +``` + +### `write_content(content, dest_path)` + +Writes content to a file in the container. + +**Parameters:** +- `content` (string): The content to write +- `dest_path` (string): The destination path in the container + +**Returns:** Command result if successful. + +**Example:** +```js +// Create a Builder +let builder = bah_new("my-container", "alpine:latest"); + +// Write content to a file +let content = "Hello, world!"; +builder.write_content(content, "/hello.txt"); +``` + +### `read_content(source_path)` + +Reads content from a file in the container. + +**Parameters:** +- `source_path` (string): The source path in the container + +**Returns:** The file content as a string if successful. + +**Example:** +```js +// Create a Builder +let builder = bah_new("my-container", "alpine:latest"); + +// Write content to a file +builder.write_content("Hello, world!", "/hello.txt"); + +// Read content from the file +let content = builder.read_content("/hello.txt"); +println(content); // Outputs: Hello, world! +``` diff --git a/src/docs/docs/sal/nerdctl.md b/src/docs/docs/sal/nerdctl.md index ba112a6..fb84e38 100644 --- a/src/docs/docs/sal/nerdctl.md +++ b/src/docs/docs/sal/nerdctl.md @@ -91,27 +91,27 @@ let remove_result = container.remove(); The Container Builder Pattern provides the following methods for configuring containers: -| Method | Description | Example | -|--------|-------------|---------| -| `reset()` | Reset configuration to defaults | `.reset()` | -| `with_port(port)` | Add a port mapping | `.with_port("8080:80")` | -| `with_ports(ports_array)` | Add multiple port mappings | `.with_ports(["8080:80", "443:443"])` | -| `with_volume(volume)` | Add a volume mount | `.with_volume("/host/path:/container/path")` | -| `with_volumes(volumes_array)` | Add multiple volume mounts | `.with_volumes(["/host/path1:/container/path1", "/host/path2:/container/path2"])` | -| `with_env(key, value)` | Add an environment variable | `.with_env("NGINX_HOST", "localhost")` | -| `with_envs(env_map)` | Add multiple environment variables | `.with_envs(#{"KEY1": "value1", "KEY2": "value2"})` | -| `with_network(network)` | Set the network | `.with_network("bridge")` | -| `with_network_alias(alias)` | Add a network alias | `.with_network_alias("web-server")` | -| `with_network_aliases(aliases_array)` | Add multiple network aliases | `.with_network_aliases(["web-server", "http-service"])` | -| `with_cpu_limit(cpus)` | Set CPU limit | `.with_cpu_limit("1.0")` | -| `with_cpu_shares(shares)` | Set CPU shares | `.with_cpu_shares("1024")` | -| `with_memory_limit(memory)` | Set memory limit | `.with_memory_limit("512m")` | -| `with_memory_swap_limit(memory_swap)` | Set memory swap limit | `.with_memory_swap_limit("1g")` | -| `with_restart_policy(policy)` | Set restart policy | `.with_restart_policy("unless-stopped")` | -| `with_health_check(cmd)` | Set health check command | `.with_health_check("curl -f http://localhost/ || exit 1")` | -| `with_health_check_options(cmd, interval, timeout, retries, start_period)` | Set health check with options | `.with_health_check_options("curl -f http://localhost/ || exit 1", "5s", "3s", 3, "10s")` | -| `with_snapshotter(snapshotter)` | Set snapshotter | `.with_snapshotter("native")` | -| `with_detach(detach)` | Set detach mode | `.with_detach(true)` | +| Method | Description | Example | +| -------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------- | +| `reset()` | Reset configuration to defaults | `.reset()` | +| `with_port(port)` | Add a port mapping | `.with_port("8080:80")` | +| `with_ports(ports_array)` | Add multiple port mappings | `.with_ports(["8080:80", "443:443"])` | +| `with_volume(volume)` | Add a volume mount | `.with_volume("/host/path:/container/path")` | +| `with_volumes(volumes_array)` | Add multiple volume mounts | `.with_volumes(["/host/path1:/container/path1", "/host/path2:/container/path2"])` | +| `with_env(key, value)` | Add an environment variable | `.with_env("NGINX_HOST", "localhost")` | +| `with_envs(env_map)` | Add multiple environment variables | `.with_envs(#{"KEY1": "value1", "KEY2": "value2"})` | +| `with_network(network)` | Set the network | `.with_network("bridge")` | +| `with_network_alias(alias)` | Add a network alias | `.with_network_alias("web-server")` | +| `with_network_aliases(aliases_array)` | Add multiple network aliases | `.with_network_aliases(["web-server", "http-service"])` | +| `with_cpu_limit(cpus)` | Set CPU limit | `.with_cpu_limit("1.0")` | +| `with_cpu_shares(shares)` | Set CPU shares | `.with_cpu_shares("1024")` | +| `with_memory_limit(memory)` | Set memory limit | `.with_memory_limit("512m")` | +| `with_memory_swap_limit(memory_swap)` | Set memory swap limit | `.with_memory_swap_limit("1g")` | +| `with_restart_policy(policy)` | Set restart policy | `.with_restart_policy("unless-stopped")` | +| `with_health_check(cmd)` | Set health check command | `.with_health_check("curl -f http://localhost/ | | exit 1")` | +| `with_health_check_options(cmd, interval, timeout, retries, start_period)` | Set health check with options | `.with_health_check_options("curl -f http://localhost/ | | exit 1", "5s", "3s", 3, "10s")` | +| `with_snapshotter(snapshotter)` | Set snapshotter | `.with_snapshotter("native")` | +| `with_detach(detach)` | Set detach mode | `.with_detach(true)` | ## Complete Example: Web Server @@ -183,16 +183,57 @@ let start_result = built_container.start(); println("The web server is running at http://localhost:8080"); ``` +## Using Local Images Created with Buildah + +When working with images created by Buildah, you may need to take additional steps to ensure nerdctl can find and use these images. This is because Buildah and nerdctl may use different storage backends by default. + +### Tagging with localhost Prefix + +One approach is to tag the Buildah-created image with a `localhost/` prefix: + +```rhai +// Create and commit a container with Buildah +let builder = bah_new("my-container", "alpine:latest"); +builder.run("echo 'Hello' > /hello.txt"); +builder.commit("my-custom-image:latest"); + +// Tag the image with localhost prefix for nerdctl compatibility +let local_image_name = "localhost/my-custom-image:latest"; +bah_image_tag("my-custom-image:latest", local_image_name); + +// Now use the image with nerdctl +let container = nerdctl_container_from_image("my-app", local_image_name) + .with_detach(true) + .build(); +``` + +### Using a Local Registry + +For more reliable interoperability, you can push the image to a local registry: + +```rhai +// Push the Buildah-created image to a local registry +bah_image_push("my-custom-image:latest", "localhost:5000/my-custom-image:latest", false); + +// Pull the image with nerdctl +nerdctl_image_pull("localhost:5000/my-custom-image:latest"); + +// Use the image +let container = nerdctl_container_from_image("my-app", "localhost:5000/my-custom-image:latest") + .with_detach(true) + .build(); +``` + ## Image Management Functions The module also provides functions for managing container images: -| Function | Description | Example | -|----------|-------------|---------| -| `nerdctl_images()` | List images in local storage | `nerdctl_images()` | -| `nerdctl_image_remove(image)` | Remove an image | `nerdctl_image_remove("nginx:latest")` | -| `nerdctl_image_push(image, destination)` | Push an image to a registry | `nerdctl_image_push("my-image:latest", "registry.example.com/my-image:latest")` | -| `nerdctl_image_tag(image, new_name)` | Add an additional name to a local image | `nerdctl_image_tag("nginx:latest", "my-nginx:latest")` | -| `nerdctl_image_pull(image)` | Pull an image from a registry | `nerdctl_image_pull("nginx:latest")` | -| `nerdctl_image_commit(container, image_name)` | Commit a container to an image | `nerdctl_image_commit("web-server", "my-nginx:latest")` | -| `nerdctl_image_build(tag, context_path)` | Build an image using a Dockerfile | `nerdctl_image_build("my-image:latest", "./")` | +| Function | Description | Example | +| --------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------- | +| `nerdctl_images()` | List images in local storage | `nerdctl_images()` | +| `nerdctl_image_remove(image)` | Remove an image | `nerdctl_image_remove("nginx:latest")` | +| `nerdctl_image_push(image, destination)` | Push an image to a registry | `nerdctl_image_push("my-image:latest", "registry.example.com/my-image:latest")` | +| `nerdctl_image_tag(image, new_name)` | Add an additional name to a local image | `nerdctl_image_tag("nginx:latest", "my-nginx:latest")` | +| `nerdctl_image_pull(image)` | Pull an image from a registry | `nerdctl_image_pull("nginx:latest")` | +| `nerdctl_image_commit(container, image_name)` | Commit a container to an image | `nerdctl_image_commit("web-server", "my-nginx:latest")` | +| `nerdctl_image_build(tag, context_path)` | Build an image using a Dockerfile | `nerdctl_image_build("my-image:latest", "./")` | diff --git a/src/docs/docs/sal/os.md b/src/docs/docs/sal/os.md index 6bf2bcb..8eaacdb 100644 --- a/src/docs/docs/sal/os.md +++ b/src/docs/docs/sal/os.md @@ -264,7 +264,7 @@ chdir("project/src"); ### `download(url, dest, min_size_kb)` -Downloads a file from a URL to a destination using the curl command. If the URL ends with a supported archive format, the file will be automatically extracted to the destination directory. +Downloads a file from a URL to a destination directory using the curl command. If the URL ends with a supported archive format, the file will be automatically extracted to the destination directory. **Supported archive formats for automatic extraction:** - `.tar.gz` @@ -274,15 +274,32 @@ Downloads a file from a URL to a destination using the curl command. If the URL **Parameters:** - `url` (string): The URL to download from -- `dest` (string): The destination path to save the file +- `dest` (string): The destination directory where the file will be saved or extracted - `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation) **Returns:** The path where the file was saved or extracted. **Example:** ```js -// Download a file -download("https://example.com/file.zip", "downloads/file.zip", 10); +// Download a file to a directory +download("https://example.com/file.zip", "downloads/", 10); +``` + +### `download_file(url, dest, min_size_kb)` + +Downloads a file from a URL to a specific file destination using the curl command. This function is designed for downloading files to a specific path, not for extracting archives. + +**Parameters:** +- `url` (string): The URL to download from +- `dest` (string): The destination file path where the file will be saved +- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation) + +**Returns:** The path where the file was saved. + +**Example:** +```js +// Download a file to a specific path +download_file("https://example.com/file.txt", "downloads/myfile.txt", 10); ``` ### `download_install(url, min_size_kb)` @@ -301,4 +318,20 @@ Downloads a file and installs it if it's a supported package format. **Example:** ```js // Download and install a package -download_install("https://example.com/package.deb", 1000); \ No newline at end of file +download_install("https://example.com/package.deb", 1000); +``` + +### `chmod_exec(path)` + +Makes a file executable (equivalent to `chmod +x` in Unix). + +**Parameters:** +- `path` (string): The path to the file to make executable + +**Returns:** A message confirming the file was made executable. + +**Example:** +```js +// Make a file executable +chmod_exec("downloads/script.sh"); +``` \ No newline at end of file diff --git a/src/os/download.rs b/src/os/download.rs index bfa1f43..c137d28 100644 --- a/src/os/download.rs +++ b/src/os/download.rs @@ -58,34 +58,167 @@ impl Error for DownloadError { /** * Download a file from URL to destination using the curl command. - * + * This function is primarily intended for downloading archives that will be extracted + * to a directory. + * * # Arguments - * + * * * `url` - The URL to download from - * * `dest` - The destination path where the file will be saved + * * `dest` - The destination directory where the file will be saved or extracted * * `min_size_kb` - Minimum required file size in KB (0 for no minimum) - * + * * # Returns - * + * * * `Ok(String)` - The path where the file was saved or extracted * * `Err(DownloadError)` - An error if the download failed - * + * * # Examples - * + * * ``` * // Download a file with no minimum size requirement - * let path = download("https://example.com/file.txt", "/tmp/file.txt", 0)?; - * + * let path = download("https://example.com/file.txt", "/tmp/", 0)?; + * * // Download a file with minimum size requirement of 100KB - * let path = download("https://example.com/file.zip", "/tmp/file.zip", 100)?; + * let path = download("https://example.com/file.zip", "/tmp/", 100)?; * ``` - * + * * # Notes - * + * * If the URL ends with .tar.gz, .tgz, .tar, or .zip, the file will be automatically * extracted to the destination directory. */ pub fn download(url: &str, dest: &str, min_size_kb: i64) -> Result { + // Create parent directories if they don't exist + let dest_path = Path::new(dest); + fs::create_dir_all(dest_path).map_err(DownloadError::CreateDirectoryFailed)?; + + // Extract filename from URL + let filename = match url.split('/').last() { + Some(name) => name, + None => return Err(DownloadError::InvalidUrl("cannot extract filename".to_string())) + }; + + // Create a full path for the downloaded file + let file_path = format!("{}/{}", dest.trim_end_matches('/'), filename); + + // Create a temporary path for downloading + let temp_path = format!("{}.download", file_path); + + // Use curl to download the file with progress bar + println!("Downloading {} to {}", url, file_path); + let output = Command::new("curl") + .args(&["--progress-bar", "--location", "--fail", "--output", &temp_path, url]) + .status() + .map_err(DownloadError::CurlExecutionFailed)?; + + if !output.success() { + return Err(DownloadError::DownloadFailed(url.to_string())); + } + + // Show file size after download + match fs::metadata(&temp_path) { + Ok(metadata) => { + let size_bytes = metadata.len(); + let size_kb = size_bytes / 1024; + let size_mb = size_kb / 1024; + if size_mb > 1 { + println!("Download complete! File size: {:.2} MB", size_bytes as f64 / (1024.0 * 1024.0)); + } else { + println!("Download complete! File size: {:.2} KB", size_bytes as f64 / 1024.0); + } + }, + Err(_) => println!("Download complete!"), + } + + // Check file size if minimum size is specified + if min_size_kb > 0 { + let metadata = fs::metadata(&temp_path).map_err(DownloadError::FileMetadataError)?; + let size_kb = metadata.len() as i64 / 1024; + if size_kb < min_size_kb { + fs::remove_file(&temp_path).map_err(DownloadError::RemoveFileFailed)?; + return Err(DownloadError::FileTooSmall(size_kb, min_size_kb)); + } + } + + // Check if it's a compressed file that needs extraction + let lower_url = url.to_lowercase(); + let is_archive = lower_url.ends_with(".tar.gz") || + lower_url.ends_with(".tgz") || + lower_url.ends_with(".tar") || + lower_url.ends_with(".zip"); + + if is_archive { + // Extract the file using the appropriate command with progress indication + println!("Extracting {} to {}", temp_path, dest); + let output = if lower_url.ends_with(".zip") { + Command::new("unzip") + .args(&["-o", &temp_path, "-d", dest]) // Removed -q for verbosity + .status() + } else if lower_url.ends_with(".tar.gz") || lower_url.ends_with(".tgz") { + Command::new("tar") + .args(&["-xzvf", &temp_path, "-C", dest]) // Added v for verbosity + .status() + } else { + Command::new("tar") + .args(&["-xvf", &temp_path, "-C", dest]) // Added v for verbosity + .status() + }; + + match output { + Ok(status) => { + if !status.success() { + return Err(DownloadError::ExtractionFailed("Error extracting archive".to_string())); + } + }, + Err(e) => return Err(DownloadError::CommandExecutionFailed(e)), + } + + // Show number of extracted files + match fs::read_dir(dest) { + Ok(entries) => { + let count = entries.count(); + println!("Extraction complete! Extracted {} files/directories", count); + }, + Err(_) => println!("Extraction complete!"), + } + + // Remove the temporary file + fs::remove_file(&temp_path).map_err(DownloadError::RemoveFileFailed)?; + + Ok(dest.to_string()) + } else { + // Just rename the temporary file to the final destination + fs::rename(&temp_path, &file_path).map_err(|e| DownloadError::CreateDirectoryFailed(e))?; + + Ok(file_path) + } +} + +/** + * Download a file from URL to a specific file destination using the curl command. + * + * # Arguments + * + * * `url` - The URL to download from + * * `dest` - The destination file path where the file will be saved + * * `min_size_kb` - Minimum required file size in KB (0 for no minimum) + * + * # Returns + * + * * `Ok(String)` - The path where the file was saved + * * `Err(DownloadError)` - An error if the download failed + * + * # Examples + * + * ``` + * // Download a file with no minimum size requirement + * let path = download_file("https://example.com/file.txt", "/tmp/file.txt", 0)?; + * + * // Download a file with minimum size requirement of 100KB + * let path = download_file("https://example.com/file.zip", "/tmp/file.zip", 100)?; + * ``` + */ +pub fn download_file(url: &str, dest: &str, min_size_kb: i64) -> Result { // Create parent directories if they don't exist let dest_path = Path::new(dest); if let Some(parent) = dest_path.parent() { @@ -131,61 +264,73 @@ pub fn download(url: &str, dest: &str, min_size_kb: i64) -> Result { - if !status.success() { - return Err(DownloadError::ExtractionFailed("Error extracting archive".to_string())); - } - }, - Err(e) => return Err(DownloadError::CommandExecutionFailed(e)), - } - - // Show number of extracted files - match fs::read_dir(dest) { - Ok(entries) => { - let count = entries.count(); - println!("Extraction complete! Extracted {} files/directories", count); - }, - Err(_) => println!("Extraction complete!"), - } - - // Remove the temporary file - fs::remove_file(&temp_path).map_err(DownloadError::RemoveFileFailed)?; - - Ok(dest.to_string()) - } else { - // Just rename the temporary file to the final destination - fs::rename(&temp_path, dest).map_err(|e| DownloadError::CreateDirectoryFailed(e))?; - - Ok(dest.to_string()) + Ok(dest.to_string()) +} + +/** + * Make a file executable (equivalent to chmod +x). + * + * # Arguments + * + * * `path` - The path to the file to make executable + * + * # Returns + * + * * `Ok(String)` - A success message including the path + * * `Err(DownloadError)` - An error if the operation failed + * + * # Examples + * + * ``` + * // Make a file executable + * chmod_exec("/path/to/file")?; + * ``` + */ +pub fn chmod_exec(path: &str) -> Result { + let path_obj = Path::new(path); + + // Check if the path exists and is a file + if !path_obj.exists() { + return Err(DownloadError::NotAFile(format!("Path does not exist: {}", path))); } + + if !path_obj.is_file() { + return Err(DownloadError::NotAFile(format!("Path is not a file: {}", path))); + } + + // Get current permissions + let metadata = fs::metadata(path).map_err(DownloadError::FileMetadataError)?; + let mut permissions = metadata.permissions(); + + // Set executable bit for user, group, and others + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mode = permissions.mode(); + // Add executable bit for user, group, and others (equivalent to +x) + let new_mode = mode | 0o111; + permissions.set_mode(new_mode); + } + + #[cfg(not(unix))] + { + // On non-Unix platforms, we can't set executable bit directly + // Just return success with a warning + return Ok(format!("Made {} executable (note: non-Unix platform, may not be fully supported)", path)); + } + + // Apply the new permissions + fs::set_permissions(path, permissions).map_err(|e| + DownloadError::CommandExecutionFailed(io::Error::new( + io::ErrorKind::Other, + format!("Failed to set executable permissions: {}", e) + )) + )?; + + Ok(format!("Made {} executable", path)) } /** @@ -223,11 +368,24 @@ pub fn download_install(url: &str, min_size_kb: i64) -> Result Result<(), Box> // Register download functions engine.register_fn("download", download); + engine.register_fn("download_file", download_file); engine.register_fn("download_install", download_install); + engine.register_fn("chmod_exec", chmod_exec); Ok(()) } @@ -175,6 +177,13 @@ pub fn download(url: &str, dest: &str, min_size_kb: i64) -> Result Result> { + os::download_file(url, dest, min_size_kb).to_rhai_error() +} + /// Wrapper for os::download_install /// /// Download a file and install it if it's a supported package format. @@ -182,6 +191,13 @@ pub fn download_install(url: &str, min_size_kb: i64) -> Result Result> { + os::chmod_exec(path).to_rhai_error() +} + /// Wrapper for os::which /// /// Check if a command exists in the system PATH. diff --git a/src/rhaiexamples/buildah.rhai b/src/rhaiexamples/buildah.rhai index 9956c1c..5c1ea23 100644 --- a/src/rhaiexamples/buildah.rhai +++ b/src/rhaiexamples/buildah.rhai @@ -107,35 +107,44 @@ println(read_script); println(`Committing container to image '${final_image_name}'...`); let commit_result = builder.commit(final_image_name); -// // Clean up the buildah container -// println("Cleaning up buildah container..."); -// builder.remove(); +// Clean up the buildah container +println("Cleaning up buildah container..."); +builder.remove(); -// // Now use nerdctl to run a container from the new image -// println("\nStarting container from the new image using nerdctl..."); +// Now use nerdctl to run a container from the new image +println("\nStarting container from the new image using nerdctl..."); -// // Create a container using the builder pattern -// // Use localhost/ prefix to ensure nerdctl uses the local image -// let local_image_name = "localhost/" + final_image_name; -// println(`Using local image: ${local_image_name}`); +// Create a container using the builder pattern +// Use localhost/ prefix to ensure nerdctl uses the local image +let local_image_name = "localhost/" + final_image_name; +println(`Using local image: ${local_image_name}`); -// // Tag the image with the localhost prefix -// let tag_result = bah_image_tag(final_image_name, local_image_name); -// println(`Tagged image as ${local_image_name}`); +// Tag the image with the localhost prefix for nerdctl compatibility +println(`Tagging image as ${local_image_name}...`); +let tag_result = bah_image_tag(final_image_name, local_image_name); -// let container = nerdctl_container_from_image("golang-nginx-demo", local_image_name) -// .with_detach(true) -// .with_port("8080:80") // Map port 80 in the container to 8080 on the host -// .with_restart_policy("unless-stopped") -// .build(); +// Print a command to check if the image exists in buildah +println("\nTo verify the image was created with buildah, run:"); +println("buildah images"); -// // Start the container -// let start_result = container.start(); +// Note: If nerdctl cannot find the image, you may need to push it to a registry +println("\nNote: If nerdctl cannot find the image, you may need to push it to a registry:"); +println("buildah push localhost/custom-golang-nginx:latest docker://localhost:5000/custom-golang-nginx:latest"); +println("nerdctl pull localhost:5000/custom-golang-nginx:latest"); -// println("\nWorkflow completed successfully!"); -// println("The web server should be running at http://localhost:8080"); -// println("You can check container logs with: nerdctl logs golang-nginx-demo"); -// println("To stop the container: nerdctl stop golang-nginx-demo"); -// println("To remove the container: nerdctl rm golang-nginx-demo"); +let container = nerdctl_container_from_image("golang-nginx-demo", local_image_name) + .with_detach(true) + .with_port("8080:80") // Map port 80 in the container to 8080 on the host + .with_restart_policy("unless-stopped") + .build(); + +// Start the container +let start_result = container.start(); + +println("\nWorkflow completed successfully!"); +println("The web server should be running at http://localhost:8080"); +println("You can check container logs with: nerdctl logs golang-nginx-demo"); +println("To stop the container: nerdctl stop golang-nginx-demo"); +println("To remove the container: nerdctl rm golang-nginx-demo"); "Buildah and nerdctl workflow completed successfully!" diff --git a/src/rhaiexamples/download_test.rhai b/src/rhaiexamples/download_test.rhai index eeb5a50..c9b5ec2 100644 --- a/src/rhaiexamples/download_test.rhai +++ b/src/rhaiexamples/download_test.rhai @@ -63,6 +63,43 @@ print(` Minimum size check passed:${success_msg}`); // Clean up test files delete(download_dir); print("Cleaned up test directory"); +//PART 4 -print("\nDownload Tests completed successfully!"); +// Test the new download_file function +print("\nTesting download_file function:"); +let text_url = "https://raw.githubusercontent.com/freeflowuniverse/herolib/main/README.md"; +let text_file_dest = `${download_dir}/README.md`; + +// Create the directory again for this test +mkdir(download_dir); + +// Download a text file using the new download_file function +let file_result = download_file(text_url, text_file_dest, 0); +print(` File downloaded to: ${file_result}`); + +// Check if the file exists and has content +let file_exists = exist(text_file_dest); +print(` File exists: ${file_exists}`); +let file_content = file_read(text_file_dest); +let content_check = if file_content.len() > 100 { "yes" } else { "no" }; +print(` File has content: ${content_check}`); + +//PART 5 + +// Test the new chmod_exec function +print("\nTesting chmod_exec function:"); +// Create a simple shell script +let script_path = `${download_dir}/test_script.sh`; +file_write(script_path, "#!/bin/sh\necho 'Hello from test script'"); + +// Make it executable +let chmod_result = chmod_exec(script_path); +print(` ${chmod_result}`); + +// Clean up test files again +delete(download_dir); +print("Cleaned up test directory"); + +print("\nAll Download Tests completed successfully!"); +"Download Tests Success" "Download Tests Success" diff --git a/src/rhaiexamples/nerdctl_install.rhai b/src/rhaiexamples/nerdctl_install.rhai index 75bc2b6..488beb0 100644 --- a/src/rhaiexamples/nerdctl_install.rhai +++ b/src/rhaiexamples/nerdctl_install.rhai @@ -2,19 +2,25 @@ fn nerdctl_download(){ - let name="nerdctl"; - let url="https://github.com/containerd/nerdctl/releases/download/v2.0.4/nerdctl-2.0.4-linux-amd64.tar.gz"; - download(url,`/tmp/${name}`,20); - copy(`/tmp/${name}/*`,"/root/hero/bin/"); - delete(`/tmp/${name}`); + // let name="nerdctl"; + // let url="https://github.com/containerd/nerdctl/releases/download/v2.0.4/nerdctl-2.0.4-linux-amd64.tar.gz"; + // download(url,`/tmp/${name}`,20000); + // copy(`/tmp/${name}/*`,"/root/hero/bin/"); + // delete(`/tmp/${name}`); - let name="containerd"; - let url="https://github.com/containerd/containerd/releases/download/v2.0.4/containerd-2.0.4-linux-amd64.tar.gz"; - download(url,`/tmp/${name}`,20); - copy(`/tmp/${name}/bin/*`,"/root/hero/bin/"); - delete(`/tmp/${name}`); + // let name="containerd"; + // let url="https://github.com/containerd/containerd/releases/download/v2.0.4/containerd-2.0.4-linux-amd64.tar.gz"; + // download(url,`/tmp/${name}`,20000); + // copy(`/tmp/${name}/bin/*`,"/root/hero/bin/"); + // delete(`/tmp/${name}`); - run("apt-get -y install buildah runc") + // run("apt-get -y install buildah runc") + + let url="https://github.com/threefoldtech/rfs/releases/download/v2.0.6/rfs"; + download_file(url,`/tmp/rfs`,10000); + chmod_exec(url); + copy(`/tmp/rfs`,"/root/hero/bin/"); + //delete(`/tmp/rfs`); }