Compare commits

..

No commits in common. "ba9103685fbe82dcf74f6e628ceb91a3f16f3fe9" and "49c879359b4ac3d6d3e9abc8ae578bba2db38537" have entirely different histories.

12 changed files with 5 additions and 593 deletions

View File

@ -49,17 +49,13 @@ sha2 = "0.10.7" # SHA-2 hash functions
tempfile = "3.5" # For temporary file operations
tera = "1.19.0" # Template engine for text rendering
thiserror = "2.0.12" # For error handling
tokio = { version = "1.45.0", features = ["full"] }
tokio = "1.45.0"
tokio-postgres = "0.7.8" # Async PostgreSQL client
tokio-test = "0.4.4"
uuid = { version = "1.16.0", features = ["v4"] }
reqwest = { version = "0.12.15", features = ["json"] }
urlencoding = "2.1.3"
zinit-client = "0.3.0"
russh = "0.42.0"
russh-keys = "0.42.0"
async-trait = "0.1.81"
futures = "0.3.30"
# Optional features for specific OS functionality
[target.'cfg(unix)'.dependencies]

View File

@ -9,7 +9,7 @@ println(`Using local image: ${local_image_name}`);
// Import the image from buildah to nerdctl
println("Importing image from buildah to nerdctl...");
process_run("buildah", ["push", "custom-golang-nginx:latest", "docker-daemon:localhost/custom-golang-nginx:latest"]);
process_run("buildah", ["push", "custom-golang-nginx:latest", "docker-daemon:custom-golang-nginx:latest"]);
let tag_result = nerdctl_image_tag("custom-golang-nginx:latest", local_image_name);

View File

@ -1,83 +0,0 @@
// Example of using the network modules in SAL
// Shows TCP port checking, HTTP URL validation, and SSH command execution
// Import system module for display
import "os" as os;
// Function to print section header
fn section(title) {
print("\n");
print("==== " + title + " ====");
print("\n");
}
// TCP connectivity checks
section("TCP Connectivity");
// Create a TCP connector
let tcp = sal::net::TcpConnector::new();
// Check if a port is open
let host = "localhost";
let port = 22;
print(`Checking if port ${port} is open on ${host}...`);
let is_open = tcp.check_port(host, port);
print(`Port ${port} is ${is_open ? "open" : "closed"}`);
// Check multiple ports
let ports = [22, 80, 443];
print(`Checking multiple ports on ${host}...`);
let port_results = tcp.check_ports(host, ports);
for result in port_results {
print(`Port ${result.0} is ${result.1 ? "open" : "closed"}`);
}
// HTTP connectivity checks
section("HTTP Connectivity");
// Create an HTTP connector
let http = sal::net::HttpConnector::new();
// Check if a URL is reachable
let url = "https://www.example.com";
print(`Checking if ${url} is reachable...`);
let is_reachable = http.check_url(url);
print(`${url} is ${is_reachable ? "reachable" : "unreachable"}`);
// Check the status code of a URL
print(`Checking status code of ${url}...`);
let status = http.check_status(url);
if status {
print(`Status code: ${status.unwrap()}`);
} else {
print("Failed to get status code");
}
// Only attempt SSH if port 22 is open
if is_open {
// SSH connectivity checks
section("SSH Connectivity");
// Create an SSH connection to localhost (if SSH server is running)
print("Attempting to connect to SSH server on localhost...");
// Using the builder pattern
let ssh = sal::net::SshConnectionBuilder::new()
.host("localhost")
.port(22)
.user(os::get_env("USER") || "root")
.build();
// Execute a simple command
print("Executing 'uname -a' command...");
let result = ssh.execute("uname -a");
if result.0 == 0 {
print("Command output:");
print(result.1);
} else {
print(`Command failed with exit code: ${result.0}`);
print(result.1);
}
}
print("\nNetwork connectivity checks completed.");

View File

@ -1,82 +0,0 @@
// Example of using the network modules in SAL through Rhai
// Shows TCP port checking, HTTP URL validation, and SSH command execution
// Function to print section header
fn section(title) {
print("\n");
print("==== " + title + " ====");
print("\n");
}
// TCP connectivity checks
section("TCP Connectivity");
// Create a TCP connector
let tcp = net::new_tcp_connector();
// Check if a port is open
let host = "localhost";
let port = 22;
print(`Checking if port ${port} is open on ${host}...`);
let is_open = tcp.check_port(host, port);
print(`Port ${port} is ${is_open ? "open" : "closed"}`);
// Check multiple ports
let ports = [22, 80, 443];
print(`Checking multiple ports on ${host}...`);
let port_results = tcp.check_ports(host, ports);
for result in port_results {
print(`Port ${result.port} is ${result.is_open ? "open" : "closed"}`);
}
// HTTP connectivity checks
section("HTTP Connectivity");
// Create an HTTP connector
let http = net::new_http_connector();
// Check if a URL is reachable
let url = "https://www.example.com";
print(`Checking if ${url} is reachable...`);
let is_reachable = http.check_url(url);
print(`${url} is ${is_reachable ? "reachable" : "unreachable"}`);
// Check the status code of a URL
print(`Checking status code of ${url}...`);
let status = http.check_status(url);
if status != () {
print(`Status code: ${status}`);
} else {
print("Failed to get status code");
}
// Get content from a URL
print(`Getting content from ${url}...`);
let content = http.get_content(url);
print(`Content length: ${content.len()} characters`);
print(`First 100 characters: ${content.substr(0, 100)}...`);
// Only attempt SSH if port 22 is open
if is_open {
// SSH connectivity checks
section("SSH Connectivity");
// Create an SSH connection to localhost (if SSH server is running)
print("Attempting to connect to SSH server on localhost...");
// Using the builder pattern
let ssh = net::new_ssh_builder()
.host("localhost")
.port(22)
.user(os::get_env("USER") || "root")
.timeout(10)
.build();
// Execute a simple command
print("Executing 'uname -a' command...");
let result = ssh.execute("uname -a");
print(`Command exit code: ${result.code}`);
print(`Command output: ${result.output}`);
}
print("\nNetwork connectivity checks completed.");

View File

@ -2,7 +2,7 @@ print("Running a command using run().log().do()...");
// The .log() method will print the command string to the console before execution.
// This is useful for debugging or tracing which commands are being run.
let result = run("echo This command is logged").log().execute();
let result = run("echo This command is logged").log().do();
print(`Command finished.`);
print(`Success: ${result.success}`);

View File

@ -8,23 +8,14 @@ fn nerdctl_download(){
copy_bin(`/tmp/${name}/*`);
delete(`/tmp/${name}`);
screen_kill("containerd");
let name="containerd";
let url="https://github.com/containerd/containerd/releases/download/v2.1.2/containerd-2.1.2-linux-amd64.tar.gz";
download(url,`/tmp/${name}`,20000);
// copy_bin(`/tmp/${name}/bin/*`);
copy_bin(`/tmp/${name}/bin/*`);
delete(`/tmp/${name}`);
let cfg = `
[[registry]]
location = "localhost:5000"
insecure = true
`;
file_write("/etc/containers/registries.conf", dedent(cfg));
screen_kill("containerd");
screen_new("containerd", "containerd");
sleep(1);
nerdctl_remove_all();
run("nerdctl run -d -p 5000:5000 --name registry registry:2").log().execute();
package_install("buildah");
package_install("runc");

View File

@ -49,7 +49,6 @@ pub mod virt;
pub mod vault;
pub mod zinit_client;
pub mod mycelium;
pub mod net;
// Version information
/// Returns the version of the SAL library

View File

@ -1,93 +0,0 @@
use std::time::Duration;
use anyhow::Result;
use reqwest::{Client, StatusCode, Url};
/// HTTP Connectivity module for checking HTTP/HTTPS connections
pub struct HttpConnector {
client: Client,
}
impl HttpConnector {
/// Create a new HTTP connector with the default configuration
pub fn new() -> Result<Self> {
let client = Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
Ok(Self { client })
}
/// Create a new HTTP connector with a custom timeout
pub fn with_timeout(timeout: Duration) -> Result<Self> {
let client = Client::builder()
.timeout(timeout)
.build()?;
Ok(Self { client })
}
/// Check if a URL is reachable
pub async fn check_url<U: AsRef<str>>(&self, url: U) -> Result<bool> {
let url_str = url.as_ref();
let url = Url::parse(url_str)?;
let result = self.client
.head(url)
.send()
.await;
Ok(result.is_ok())
}
/// Check a URL and return the status code if reachable
pub async fn check_status<U: AsRef<str>>(&self, url: U) -> Result<Option<StatusCode>> {
let url_str = url.as_ref();
let url = Url::parse(url_str)?;
let result = self.client
.head(url)
.send()
.await;
match result {
Ok(response) => Ok(Some(response.status())),
Err(_) => Ok(None),
}
}
/// Get the content of a URL
pub async fn get_content<U: AsRef<str>>(&self, url: U) -> Result<String> {
let url_str = url.as_ref();
let url = Url::parse(url_str)?;
let response = self.client
.get(url)
.send()
.await?;
if !response.status().is_success() {
return Err(anyhow::anyhow!(
"HTTP request failed with status: {}",
response.status()
));
}
let content = response.text().await?;
Ok(content)
}
/// Verify that a URL responds with a specific status code
pub async fn verify_status<U: AsRef<str>>(&self, url: U, expected_status: StatusCode) -> Result<bool> {
match self.check_status(url).await? {
Some(status) => Ok(status == expected_status),
None => Ok(false),
}
}
}
impl Default for HttpConnector {
fn default() -> Self {
Self::new().expect("Failed to create default HttpConnector")
}
}

View File

@ -1,8 +0,0 @@
pub mod ssh;
pub mod tcp;
pub mod http;
// Re-export main types for a cleaner API
pub use ssh::{SshConnection, SshConnectionBuilder};
pub use tcp::TcpConnector;
pub use http::HttpConnector;

View File

@ -1,145 +0,0 @@
use std::path::PathBuf;
use std::time::Duration;
use std::process::Stdio;
use anyhow::Result;
use tokio::io::{AsyncReadExt, BufReader};
use tokio::process::Command;
/// SSH Connection that uses the system's SSH client
pub struct SshConnection {
host: String,
port: u16,
user: String,
identity_file: Option<PathBuf>,
timeout: Duration,
}
impl SshConnection {
/// Execute a command over SSH and return its output
pub async fn execute(&self, command: &str) -> Result<(i32, String)> {
let mut args = Vec::new();
// Add SSH options
args.push("-o".to_string());
args.push(format!("ConnectTimeout={}", self.timeout.as_secs()));
// Don't check host key to avoid prompts
args.push("-o".to_string());
args.push("StrictHostKeyChecking=no".to_string());
// Specify port if not default
if self.port != 22 {
args.push("-p".to_string());
args.push(self.port.to_string());
}
// Add identity file if provided
if let Some(identity) = &self.identity_file {
args.push("-i".to_string());
args.push(identity.to_string_lossy().to_string());
}
// Add user and host
args.push(format!("{}@{}", self.user, self.host));
// Add the command to execute
args.push(command.to_string());
// Run the SSH command
let mut child = Command::new("ssh")
.args(&args)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
// Collect stdout and stderr
let stdout = child.stdout.take().unwrap();
let stderr = child.stderr.take().unwrap();
let mut stdout_reader = BufReader::new(stdout);
let mut stderr_reader = BufReader::new(stderr);
let mut output = String::new();
stdout_reader.read_to_string(&mut output).await?;
let mut error_output = String::new();
stderr_reader.read_to_string(&mut error_output).await?;
// If there's error output, append it to the regular output
if !error_output.is_empty() {
if !output.is_empty() {
output.push_str("\n");
}
output.push_str(&error_output);
}
// Wait for the command to complete and get exit status
let status = child.wait().await?;
let code = status.code().unwrap_or(-1);
Ok((code, output))
}
/// Check if the host is reachable via SSH
pub async fn ping(&self) -> Result<bool> {
let result = self.execute("echo 'Connection successful'").await?;
Ok(result.0 == 0)
}
}
/// Builder for SSH connections
pub struct SshConnectionBuilder {
host: String,
port: u16,
user: String,
identity_file: Option<PathBuf>,
timeout: Duration,
}
impl SshConnectionBuilder {
pub fn new() -> Self {
Self {
host: "localhost".to_string(),
port: 22,
user: "root".to_string(),
identity_file: None,
timeout: Duration::from_secs(10),
}
}
pub fn host<S: Into<String>>(mut self, host: S) -> Self {
self.host = host.into();
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = port;
self
}
pub fn user<S: Into<String>>(mut self, user: S) -> Self {
self.user = user.into();
self
}
pub fn identity_file(mut self, path: PathBuf) -> Self {
self.identity_file = Some(path);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn build(self) -> SshConnection {
SshConnection {
host: self.host,
port: self.port,
user: self.user,
identity_file: self.identity_file,
timeout: self.timeout,
}
}
}

View File

@ -1,74 +0,0 @@
use std::net::{IpAddr, SocketAddr};
use std::time::Duration;
use anyhow::Result;
use tokio::net::TcpStream;
use tokio::time::timeout;
/// TCP Connectivity module for checking TCP connections
pub struct TcpConnector {
timeout: Duration,
}
impl TcpConnector {
/// Create a new TCP connector with the default timeout (5 seconds)
pub fn new() -> Self {
Self {
timeout: Duration::from_secs(5),
}
}
/// Create a new TCP connector with a custom timeout
pub fn with_timeout(timeout: Duration) -> Self {
Self { timeout }
}
/// Check if a TCP port is open on a host
pub async fn check_port<A: Into<IpAddr>>(&self, host: A, port: u16) -> Result<bool> {
let addr = SocketAddr::new(host.into(), port);
let connect_future = TcpStream::connect(addr);
match timeout(self.timeout, connect_future).await {
Ok(Ok(_)) => Ok(true),
Ok(Err(_)) => Ok(false),
Err(_) => Ok(false), // Timeout occurred
}
}
/// Check if multiple TCP ports are open on a host
pub async fn check_ports<A: Into<IpAddr> + Clone>(&self, host: A, ports: &[u16]) -> Result<Vec<(u16, bool)>> {
let mut results = Vec::with_capacity(ports.len());
for &port in ports {
let is_open = self.check_port(host.clone(), port).await?;
results.push((port, is_open));
}
Ok(results)
}
/// Check if a host is reachable on the network using ICMP ping
pub async fn ping<S: AsRef<str>>(&self, host: S) -> Result<bool> {
// Convert to owned strings to avoid borrowing issues
let host_str = host.as_ref().to_string();
let timeout_secs = self.timeout.as_secs().to_string();
// Run the ping command with explicit arguments
let status = tokio::process::Command::new("ping")
.arg("-c")
.arg("1") // Just one ping
.arg("-W")
.arg(timeout_secs) // Timeout in seconds
.arg(host_str) // Host to ping
.output()
.await?;
Ok(status.status.success())
}
}
impl Default for TcpConnector {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,89 +0,0 @@
//! Rhai wrappers for network module functions
//!
//! This module provides Rhai wrappers for network connectivity functions.
use rhai::{Engine, EvalAltResult};
use crate::net::TcpConnector;
use super::error::register_error_types;
/// Register network module functions with the Rhai engine
///
/// # Arguments
///
/// * `engine` - The Rhai engine to register the functions with
///
/// # Returns
///
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
pub fn create_module() -> rhai::Module {
let mut module = rhai::Module::new();
// Register basic TCP functions
module.set_native_fn("tcp_check", tcp_check);
module.set_native_fn("tcp_ping", tcp_ping);
module
}
/// Register network module functions with the Rhai engine
pub fn register_net_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
// Register error types
register_error_types(engine)?;
// TCP functions
engine.register_fn("tcp_check", tcp_check);
engine.register_fn("tcp_ping", tcp_ping);
Ok(())
}
/// Check if a TCP port is open
pub fn tcp_check(host: &str, port: i64) -> bool {
let connector = TcpConnector::new();
// Create a simple runtime to run the async function
match tokio::runtime::Builder::new_current_thread()
.enable_all()
.build() {
Ok(rt) => {
rt.block_on(async {
// Resolve host name first
let sock_addr = format!("{}:{}", host, port);
match tokio::net::lookup_host(sock_addr).await {
Ok(mut addrs) => {
if let Some(addr) = addrs.next() {
match connector.check_port(addr.ip(), port as u16).await {
Ok(is_open) => is_open,
Err(_) => false,
}
} else {
false
}
},
Err(_) => false,
}
})
},
Err(_) => false,
}
}
/// Ping a host using ICMP
pub fn tcp_ping(host: &str) -> bool {
let connector = TcpConnector::new();
// Create a simple runtime to run the async function
match tokio::runtime::Builder::new_current_thread()
.enable_all()
.build() {
Ok(rt) => {
rt.block_on(async {
match connector.ping(host).await {
Ok(result) => result,
Err(_) => false,
}
})
},
Err(_) => false,
}
}