chore: remove dead core/parmanode crate

The parmanode compatibility layer was scaffolded but never wired up —
zero imports or calls from anywhere in the codebase. Closes gitea#1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-26 15:33:13 +00:00
parent 1d9fe06f97
commit f7a57b8f1f
6 changed files with 1 additions and 254 deletions

View File

@@ -4,7 +4,6 @@ resolver = "2"
members = [
"archipelago",
"container",
"parmanode",
"performance",
"security",
]

View File

@@ -34,7 +34,7 @@ futures-util = "0.3"
archipelago-container = { path = "../container" }
archipelago-security = { path = "../security" }
archipelago-performance = { path = "../performance" }
archipelago-parmanode = { path = "../parmanode" }
# Database (optional for now - can use SQLite or skip)
# sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio-rustls"] }

View File

@@ -1,18 +0,0 @@
[package]
name = "archipelago-parmanode"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
anyhow = "1.0"
thiserror = "1.0"
archipelago-container = { path = "../container" }
log = "0.4"
tracing = "0.1"
[lib]
name = "archipelago_parmanode"
path = "src/lib.rs"

View File

@@ -1,101 +0,0 @@
// Parmanode to App Manifest converter
// Converts Parmanode module structure to Archipelago app manifest format
use archipelago_container::AppManifest;
use anyhow::{Context, Result};
use std::path::PathBuf;
use tokio::fs;
use tracing::info;
pub struct ParmanodeConverter;
impl ParmanodeConverter {
pub fn new() -> Self {
Self
}
/// Convert a Parmanode module directory to an App Manifest
pub async fn convert_to_manifest(&self, module_path: &PathBuf) -> Result<AppManifest> {
info!("Converting Parmanode module to manifest: {:?}", module_path);
// Read Parmanode module metadata if available
let module_name = module_path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown")
.to_string();
// Try to detect what the module installs
let install_script = module_path.join("install.sh");
let script_content = if install_script.exists() {
fs::read_to_string(&install_script).await.ok()
} else {
None
};
// Infer app details from script content
let (app_id, image) = self.infer_from_script(&script_content)?;
// Create a basic manifest
let manifest_yaml = format!(
r#"
app:
id: {}
name: {}
version: 1.0.0
description: Converted from Parmanode module
container:
image: {}
pull_policy: if-not-present
resources:
cpu_limit: 1
memory_limit: 512Mi
disk_limit: 10Gi
security:
capabilities: []
readonly_root: true
network_policy: isolated
"#,
app_id, module_name, image
);
AppManifest::from_str(&manifest_yaml)
.context("Failed to create manifest from Parmanode module")
}
fn infer_from_script(&self, script_content: &Option<String>) -> Result<(String, String)> {
let content = script_content.as_deref().unwrap_or("");
// Try to detect Bitcoin Core
if content.contains("bitcoind") || content.contains("bitcoin-core") {
return Ok(("bitcoin-core".to_string(), "bitcoin/bitcoin:24.0".to_string()));
}
// Try to detect LND
if content.contains("lnd") && !content.contains("lightning") {
return Ok(("lnd".to_string(), "lightninglabs/lnd:v0.18.0".to_string()));
}
// Try to detect Core Lightning
if content.contains("clightning") || content.contains("core-lightning") {
return Ok(("core-lightning".to_string(), "elementsproject/lightningd:v23.08.2".to_string()));
}
// Try to detect Electrs
if content.contains("electrs") {
return Ok(("electrs".to_string(), "romanz/electrs:v0.10.0".to_string()));
}
// Default fallback — pin Alpine to a specific version
Ok(("parmanode-module".to_string(), "alpine:3.19".to_string()))
}
}
impl Default for ParmanodeConverter {
fn default() -> Self {
Self::new()
}
}

View File

@@ -1,5 +0,0 @@
pub mod script_runner;
pub mod converter;
pub use script_runner::ParmanodeScriptRunner;
pub use converter::ParmanodeConverter;

View File

@@ -1,128 +0,0 @@
// Parmanode script runner - executes Parmanode installation scripts in containers
// Provides compatibility layer for existing Parmanode modules
use archipelago_container::PodmanClient;
use anyhow::{Context, Result};
use std::path::PathBuf;
use std::process::Command;
use tokio::fs;
use tracing::{info, warn};
pub struct ParmanodeScriptRunner {
_podman: PodmanClient,
_scripts_dir: PathBuf,
}
impl ParmanodeScriptRunner {
pub fn new(scripts_dir: PathBuf) -> Self {
Self {
_podman: PodmanClient::new("archipelago".to_string()),
_scripts_dir: scripts_dir,
}
}
/// 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
let _container_name = format!("parmanode-{}", script_name);
// 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")))
}
}
}
}