2026-01-24 22:01:51 +00:00
|
|
|
// Parmanode script runner - executes Parmanode installation scripts in containers
|
|
|
|
|
// Provides compatibility layer for existing Parmanode modules
|
|
|
|
|
|
Update archipelago: API, auth, container, parmanode, performance, security
- API handler, RPC, and server updates
- Auth and coding rules
- Container data manager, dev orchestrator, health monitor, podman client
- Parmanode script runner
- Performance resource manager
- Security container policies and secrets manager
- Add build scripts and documentation
2026-01-27 22:27:17 +00:00
|
|
|
use archipelago_container::PodmanClient;
|
2026-01-24 22:01:51 +00:00
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
use tokio::fs;
|
|
|
|
|
use tracing::{info, warn};
|
|
|
|
|
|
|
|
|
|
pub struct ParmanodeScriptRunner {
|
Update archipelago: API, auth, container, parmanode, performance, security
- API handler, RPC, and server updates
- Auth and coding rules
- Container data manager, dev orchestrator, health monitor, podman client
- Parmanode script runner
- Performance resource manager
- Security container policies and secrets manager
- Add build scripts and documentation
2026-01-27 22:27:17 +00:00
|
|
|
_podman: PodmanClient,
|
|
|
|
|
_scripts_dir: PathBuf,
|
2026-01-24 22:01:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ParmanodeScriptRunner {
|
|
|
|
|
pub fn new(scripts_dir: PathBuf) -> Self {
|
|
|
|
|
Self {
|
Update archipelago: API, auth, container, parmanode, performance, security
- API handler, RPC, and server updates
- Auth and coding rules
- Container data manager, dev orchestrator, health monitor, podman client
- Parmanode script runner
- Performance resource manager
- Security container policies and secrets manager
- Add build scripts and documentation
2026-01-27 22:27:17 +00:00
|
|
|
_podman: PodmanClient::new("archipelago".to_string()),
|
|
|
|
|
_scripts_dir: scripts_dir,
|
2026-01-24 22:01:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Detect if a path contains a Parmanode script
|
|
|
|
|
pub fn is_parmanode_script(&self, path: &PathBuf) -> bool {
|
|
|
|
|
// Check for common Parmanode script patterns
|
|
|
|
|
path.file_name()
|
|
|
|
|
.and_then(|name| name.to_str())
|
|
|
|
|
.map(|name| {
|
|
|
|
|
name.ends_with(".sh") && (
|
|
|
|
|
name.contains("parmanode") ||
|
|
|
|
|
name.contains("bitcoin") ||
|
|
|
|
|
name.contains("lightning") ||
|
|
|
|
|
name.contains("electrs")
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run a Parmanode script in an isolated container
|
|
|
|
|
pub async fn run_script(&self, script_path: &PathBuf) -> Result<()> {
|
|
|
|
|
info!("Running Parmanode script: {:?}", script_path);
|
|
|
|
|
|
|
|
|
|
// Create a temporary container manifest for the script
|
|
|
|
|
let script_name = script_path
|
|
|
|
|
.file_stem()
|
|
|
|
|
.and_then(|s| s.to_str())
|
|
|
|
|
.unwrap_or("parmanode-script");
|
|
|
|
|
|
|
|
|
|
// Create a minimal container to run the script
|
Update archipelago: API, auth, container, parmanode, performance, security
- API handler, RPC, and server updates
- Auth and coding rules
- Container data manager, dev orchestrator, health monitor, podman client
- Parmanode script runner
- Performance resource manager
- Security container policies and secrets manager
- Add build scripts and documentation
2026-01-27 22:27:17 +00:00
|
|
|
let _container_name = format!("parmanode-{}", script_name);
|
2026-01-24 22:01:51 +00:00
|
|
|
|
|
|
|
|
// Copy script to a location accessible by containers
|
|
|
|
|
let script_content = fs::read_to_string(script_path).await
|
|
|
|
|
.context("Failed to read Parmanode script")?;
|
|
|
|
|
|
|
|
|
|
// Create a wrapper script that runs in Alpine
|
|
|
|
|
let wrapper_script = format!(
|
|
|
|
|
r#"#!/bin/sh
|
|
|
|
|
set -e
|
|
|
|
|
{}
|
|
|
|
|
"#,
|
|
|
|
|
script_content
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Write wrapper to temp location
|
|
|
|
|
let temp_script = format!("/tmp/parmanode-{}.sh", script_name);
|
|
|
|
|
fs::write(&temp_script, wrapper_script).await
|
|
|
|
|
.context("Failed to write wrapper script")?;
|
|
|
|
|
|
|
|
|
|
// Make executable
|
|
|
|
|
Command::new("chmod")
|
|
|
|
|
.arg("+x")
|
|
|
|
|
.arg(&temp_script)
|
|
|
|
|
.output()
|
|
|
|
|
.context("Failed to make script executable")?;
|
|
|
|
|
|
|
|
|
|
// Run script in a temporary Alpine container
|
|
|
|
|
let output = Command::new("podman")
|
|
|
|
|
.arg("run")
|
|
|
|
|
.arg("--rm")
|
|
|
|
|
.arg("--volume")
|
|
|
|
|
.arg(format!("{}:/script.sh:ro", temp_script))
|
|
|
|
|
.arg("alpine:latest")
|
|
|
|
|
.arg("sh")
|
|
|
|
|
.arg("/script.sh")
|
|
|
|
|
.output()
|
|
|
|
|
.context("Failed to execute Parmanode script in container")?;
|
|
|
|
|
|
|
|
|
|
if !output.status.success() {
|
|
|
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
|
|
|
return Err(anyhow::anyhow!("Parmanode script failed: {}", stderr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Parmanode script completed successfully");
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Install a Parmanode module (runs script and sets up container)
|
|
|
|
|
pub async fn install_module(&self, module_path: &PathBuf) -> Result<String> {
|
|
|
|
|
// Find the main installation script
|
|
|
|
|
let install_script = module_path.join("install.sh");
|
|
|
|
|
if !install_script.exists() {
|
|
|
|
|
return Err(anyhow::anyhow!("No install.sh found in Parmanode module"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the installation script
|
|
|
|
|
self.run_script(&install_script).await?;
|
|
|
|
|
|
|
|
|
|
// Try to convert to app manifest for future management
|
|
|
|
|
let converter = crate::converter::ParmanodeConverter::new();
|
|
|
|
|
match converter.convert_to_manifest(module_path).await {
|
|
|
|
|
Ok(manifest) => {
|
|
|
|
|
info!("Converted Parmanode module to app manifest");
|
|
|
|
|
// TODO: Save manifest for future use
|
|
|
|
|
Ok(manifest.app.id)
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
warn!("Failed to convert Parmanode module: {}", e);
|
|
|
|
|
// Return a generic ID
|
|
|
|
|
Ok(format!("parmanode-{}",
|
|
|
|
|
module_path.file_name()
|
|
|
|
|
.and_then(|n| n.to_str())
|
|
|
|
|
.unwrap_or("module")))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|