feat: add HeroRun remote container management library

- Introduce Executor for remote container orchestration
- Add Container lifecycle management with tmux
- Support Alpine and Alpine Python base images
- Auto-install core dependencies on remote node
- Include full usage examples and updated README
This commit is contained in:
Mahmoud-Emad
2025-09-03 18:32:47 +03:00
parent 0ee57a8075
commit 8d03eb822d
21 changed files with 1413 additions and 11 deletions

View File

@@ -0,0 +1,105 @@
# HeroRun - AI Agent Optimized Container Management
**Production-ready scripts for fast remote command execution**
## 🎯 Purpose
Optimized for AI agents that need rapid, reliable command execution with minimal latency and clean output.
## 🏗️ Base Image Types
HeroRun supports different base images through the `BaseImage` enum:
```v
pub enum BaseImage {
alpine // Standard Alpine Linux minirootfs (~5MB)
alpine_python // Alpine Linux with Python 3 pre-installed
}
```
### Usage Examples
**Standard Alpine Container:**
```v
base_image: .alpine // Default - minimal Alpine Linux
```
**Alpine with Python:**
```v
base_image: .alpine_python // Python 3 + pip pre-installed
```
## 📋 Three Scripts
### 1. `setup.vsh` - Environment Preparation
Creates container infrastructure on remote node.
```bash
./setup.vsh
```
**Output:** `Setup complete`
### 2. `execute.vsh` - Fast Command Execution
Executes commands on remote node with clean output only.
```bash
./execute.vsh "command" [context_id]
```
**Examples:**
```bash
./execute.vsh "ls /containers"
./execute.vsh "whoami"
./execute.vsh "echo 'Hello World'"
```
**Output:** Command result only (no verbose logging)
### 3. `cleanup.vsh` - Complete Teardown
Removes container and cleans up all resources.
```bash
./cleanup.vsh
```
**Output:** `Cleanup complete`
## ⚡ Performance Features
- **Clean Output**: Execute returns only command results
- **No Verbose Logging**: Silent operation for production use
- **Fast Execution**: Direct SSH without tmux overhead
- **AI Agent Ready**: Perfect for automated command execution
## 🚀 Usage Pattern
```bash
# Setup once
./setup.vsh
# Execute many commands (fast)
./execute.vsh "ls -la"
./execute.vsh "ps aux"
./execute.vsh "df -h"
# Cleanup when done
./cleanup.vsh
```
## 🎯 AI Agent Integration
Perfect for AI agents that need:
- Rapid command execution
- Clean, parseable output
- Minimal setup overhead
- Production-ready reliability
Each execute call returns only the command output, making it ideal for AI agents to parse and process results.

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
fn main() {
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor using proper modules
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'ai_agent_container'
keyname: 'id_ed25519'
)!
// Cleanup using tmux and osal modules
executor.cleanup()!
println('Cleanup complete')
}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
import os
fn main() {
// Get command from command line args
if os.args.len < 2 {
println('Usage: ./execute.vsh "command" [context_id]')
exit(1)
}
cmd := os.args[1]
// context_id := if os.args.len > 2 { os.args[2] } else { 'default' }
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor using proper modules
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'ai_agent_container'
keyname: 'id_ed25519'
)!
// Execute command using osal module for clean output
output := executor.execute(cmd)!
// Output only the command result
print(output)
}

View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
echo "🎉 Hello from custom container entry point!"
echo "Container ID: $(hostname)"
echo "Current time: $(date)"
echo "Working directory: $(pwd)"
echo "Available commands:"
ls /bin | head -10
echo "..."
echo "✅ Container is working perfectly!"

View File

@@ -0,0 +1,74 @@
#!/bin/sh
set -e
echo "🐍 Starting Python HTTP server..."
# Allow overriding port via environment variable (default: 8000)
PORT=${PORT:-8000}
HOST=${HOST:-0.0.0.0}
# Check if Python is available
if ! command -v python >/dev/null 2>&1 && ! command -v python3 >/dev/null 2>&1; then
echo "❌ Python not found in this container"
echo "💡 To use Python server, you need a container with Python pre-installed"
echo " For now, starting a simple HTTP server using busybox httpd..."
# Create a simple index.html
mkdir -p /tmp/www
cat > /tmp/www/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Container HTTP Server</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.container { max-width: 600px; margin: 0 auto; }
.status { color: #28a745; }
.info { background: #f8f9fa; padding: 20px; border-radius: 5px; }
</style>
</head>
<body>
<div class="container">
<h1>🎉 Container HTTP Server</h1>
<p class="status">✅ Container is running successfully!</p>
<div class="info">
<h3>Server Information:</h3>
<ul>
<li><strong>Server:</strong> BusyBox httpd</li>
<li><strong>Port:</strong> 8000</li>
<li><strong>Container:</strong> Alpine Linux</li>
<li><strong>Status:</strong> Active</li>
</ul>
</div>
<p><em>Note: Python was not available, so we're using BusyBox httpd instead.</em></p>
</div>
</body>
</html>
EOF
echo "📁 Created simple web content at /tmp/www/"
echo "🌐 Would start HTTP server on $HOST:$PORT (if httpd was available)"
echo ""
echo "🎉 Container executed successfully!"
echo "✅ Entry point script is working"
echo "📋 Container contents:"
ls -la /tmp/www/
echo ""
echo "📄 Sample web content:"
cat /tmp/www/index.html | head -10
echo "..."
echo ""
echo "💡 To run a real HTTP server, use a container image with Python or httpd pre-installed"
else
# Use python3 if available, otherwise python
PYTHON_CMD="python3"
if ! command -v python3 >/dev/null 2>&1; then
PYTHON_CMD="python"
fi
echo "✅ Found Python: $PYTHON_CMD"
echo "🌐 Starting Python HTTP server on $HOST:$PORT"
# Use exec so signals (like Ctrl+C) are properly handled
exec $PYTHON_CMD -m http.server "$PORT" --bind "$HOST"
fi

21
examples/virt/herorun/setup.vsh Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
fn main() {
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor using proper module integration
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'ai_agent_container'
keyname: 'id_ed25519'
)!
// Setup using sshagent, tmux, hetznermanager, and osal modules
executor.setup()!
println('Setup complete')
}

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
fn main() {
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor with Alpine Python base image
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'python_alpine_container'
keyname: 'id_ed25519'
image_script: 'examples/virt/herorun/images/python_server.sh'
base_image: .alpine_python // Use Alpine with Python pre-installed
)!
// Setup container
executor.setup()!
// Create container with Python Alpine base and Python server script
mut container := executor.get_or_create_container(
name: 'python_alpine_container'
image_script: 'examples/virt/herorun/images/python_server.sh'
base_image: .alpine_python
)!
println(' Setup complete with Python Alpine container')
println('Container: python_alpine_container')
println('Base image: Alpine Linux with Python 3 pre-installed')
println('Entry point: python_server.sh')
// Test the container to show Python is available
println('\n🐍 Testing Python availability...')
python_test := executor.execute('runc exec python_alpine_container python3 --version') or {
println(' Python test failed: ${err}')
return
}
println(' Python version: ${python_test}')
println('\n🚀 Running Python HTTP server...')
println('Note: This will start the server and exit (use runc run for persistent server)')
// Run the container to start the Python server
result := executor.execute('runc run python_alpine_container') or {
println(' Container execution failed: ${err}')
return
}
println('📋 Server output:')
println(result)
println('\n🎉 Python Alpine container executed successfully!')
println('💡 The Python HTTP server would run on port 8000 if started persistently')
}

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
fn main() {
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor with image script for Python server
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'python_server_container'
keyname: 'id_ed25519'
image_script: 'examples/virt/herorun/images/python_server.sh' // Path to entry point script
)!
// Setup using sshagent, tmux, hetznermanager, and osal modules
executor.setup()!
// Create container with the Python server script
mut container := executor.get_or_create_container(
name: 'python_server_container'
image_script: 'examples/virt/herorun/images/python_server.sh'
)!
println('Setup complete with Python server container')
println('Container: python_server_container')
println('Entry point: examples/virt/herorun/images/python_server.sh (Python HTTP server)')
println('To start the server: runc run python_server_container')
}

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.virt.herorun
fn main() {
// Create user with SSH key using sshagent module
mut user := herorun.new_user(keyname: 'id_ed25519')!
// Create executor with hello world script
mut executor := herorun.new_executor(
node_ip: '65.21.132.119'
user: 'root'
container_id: 'hello_world_container'
keyname: 'id_ed25519'
image_script: 'examples/virt/herorun/images/hello_world.sh'
)!
// Setup container
executor.setup()!
// Create container with hello world script
mut container := executor.get_or_create_container(
name: 'hello_world_container'
image_script: 'examples/virt/herorun/images/hello_world.sh'
)!
println(' Setup complete with Hello World container')
println('Container: hello_world_container')
println('Entry point: hello_world.sh')
// Run the container to demonstrate it works
println('\n🚀 Running container...')
result := executor.execute('runc run hello_world_container') or {
println(' Container execution failed: ${err}')
return
}
println('📋 Container output:')
println(result)
println('\n🎉 Container executed successfully!')
}

View File

@@ -1,4 +0,0 @@
mkdir -p cd /tmp/busyb
cd /tmp/busyb
podman export $(podman create busybox) | tar -C /tmp/busyb -xvf -

View File

@@ -1 +0,0 @@
apt install

View File

@@ -1,6 +0,0 @@
## busybox
- use docker, expand it into a directory