refactor: Migrate container management to heropods module
- Remove `herorun` module and related scripts - Introduce `heropods` module for container management - Enhance `tmux` module with pane clearing and creation - Update `Container` methods to use `osal.Command` result - Improve `ContainerFactory` for image & container handling
This commit is contained in:
3
examples/virt/herorun/herorun2.vsh → examples/virt/heropods/heropods.vsh
Normal file → Executable file
3
examples/virt/herorun/herorun2.vsh → examples/virt/heropods/heropods.vsh
Normal file → Executable file
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
import freeflowuniverse.herolib.virt.heropods
|
||||
@@ -1,105 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
// 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')
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
import os
|
||||
|
||||
// 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)
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
// 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')
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
// 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')
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
// 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')
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
|
||||
// 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!')
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
// Create container factory
|
||||
mut factory := herorun.new(reset: false)!
|
||||
|
||||
// Create a new Alpine container
|
||||
mut container := factory.new(name: 'test-alpine', image: .alpine_3_20)!
|
||||
|
||||
// Start the container
|
||||
container.start()!
|
||||
|
||||
// Execute commands in the container
|
||||
result := container.exec(cmd: 'ls -la /', stdout: true)!
|
||||
console.print_debug('Container ls result: ${result}')
|
||||
|
||||
// Test file operations
|
||||
container.exec(cmd: 'echo "Hello from container" > /tmp/test.txt', stdout: false)!
|
||||
content := container.exec(cmd: 'cat /tmp/test.txt', stdout: false)!
|
||||
console.print_debug('File content: ${content}')
|
||||
|
||||
// Get container status and resource usage
|
||||
status := container.status()!
|
||||
cpu := container.cpu_usage()!
|
||||
mem := container.mem_usage()!
|
||||
|
||||
console.print_debug('Container status: ${status}')
|
||||
console.print_debug('CPU usage: ${cpu}%')
|
||||
console.print_debug('Memory usage: ${mem} MB')
|
||||
|
||||
// Clean up
|
||||
container.stop()!
|
||||
container.delete()!
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.virt.herorun
|
||||
import freeflowuniverse.herolib.builder
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
// Create container
|
||||
mut factory := herorun.new()!
|
||||
mut container := factory.new(name: 'builder-test', image: .ubuntu_24_04)!
|
||||
container.start()!
|
||||
|
||||
// Get builder node for the container
|
||||
mut node := container.node()!
|
||||
|
||||
// Use builder methods to interact with container
|
||||
node.file_write('/tmp/script.sh', '
|
||||
#!/bin/bash
|
||||
echo "Running from builder node"
|
||||
whoami
|
||||
pwd
|
||||
ls -la /
|
||||
')!
|
||||
|
||||
result := node.exec(cmd: 'chmod +x /tmp/script.sh && /tmp/script.sh', stdout: true)!
|
||||
console.print_debug('Builder execution result: ${result}')
|
||||
|
||||
// Test file operations through builder
|
||||
exists := node.file_exists('/tmp/script.sh')
|
||||
console.print_debug('Script exists: ${exists}')
|
||||
|
||||
content := node.file_read('/tmp/script.sh')!
|
||||
console.print_debug('Script content: ${content}')
|
||||
|
||||
// Clean up
|
||||
container.stop()!
|
||||
container.delete()!
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/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!"
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user