119 lines
3.3 KiB
V
119 lines
3.3 KiB
V
module herorun2
|
||
|
||
import os
|
||
import incubaid.herolib.ui.console
|
||
import incubaid.herolib.osal.tmux
|
||
|
||
// HetznerBackend implements NodeBackend for Hetzner cloud servers
|
||
pub struct HetznerBackend {
|
||
pub mut:
|
||
node Node
|
||
}
|
||
|
||
// Create new Hetzner backend
|
||
pub fn new_hetzner_backend(args NewNodeArgs) !HetznerBackend {
|
||
console.print_header('🖥️ Creating Hetzner Backend')
|
||
console.print_stdout('IP: ${args.node_ip}')
|
||
|
||
node := Node{
|
||
settings: NodeSettings{
|
||
node_ip: args.node_ip
|
||
user: args.user
|
||
}
|
||
}
|
||
|
||
return HetznerBackend{
|
||
node: node
|
||
}
|
||
}
|
||
|
||
// Implement NodeBackend interface
|
||
pub fn (mut h HetznerBackend) connect(args NodeConnectArgs) ! {
|
||
console.print_header('🔌 Connecting to Hetzner node')
|
||
console.print_item('Node IP: ${h.node.settings.node_ip}')
|
||
console.print_item('User: ${h.node.settings.user}')
|
||
|
||
// Basic SSH connection test
|
||
cmd := 'ssh ${h.node.settings.user}@${h.node.settings.node_ip} -o StrictHostKeyChecking=no exit'
|
||
stream_command(cmd)!
|
||
console.print_green('Connection successful')
|
||
|
||
// Ensure required packages are installed
|
||
console.print_header('📦 Ensuring required packages')
|
||
install_cmd := 'ssh ${h.node.settings.user}@${h.node.settings.node_ip} "apt-get update && apt-get install -y runc tmux curl xz-utils"'
|
||
stream_command(install_cmd)!
|
||
console.print_green('Dependencies installed')
|
||
}
|
||
|
||
pub fn (h HetznerBackend) send_command(args SendCommandArgs) ! {
|
||
console.print_header('💻 Running remote command on Hetzner')
|
||
console.print_item('Command: ${args.cmd}')
|
||
remote_cmd := 'ssh ${h.node.settings.user}@${h.node.settings.node_ip} "${args.cmd}"'
|
||
stream_command(remote_cmd)!
|
||
}
|
||
|
||
pub fn (mut h HetznerBackend) get_or_create_container(args NewContainerArgs) !Container {
|
||
console.print_header('📦 Get or create container: ${args.name}')
|
||
|
||
// Check if container exists
|
||
check_cmd := 'ssh ${h.node.settings.user}@${h.node.settings.node_ip} "runc list | grep ${args.name}"'
|
||
code := os.system(check_cmd)
|
||
|
||
if code != 0 {
|
||
console.print_stdout('Container not found, creating...')
|
||
h.create_container(args.name)!
|
||
} else {
|
||
console.print_stdout('Container already exists.')
|
||
}
|
||
|
||
// Create tmux session wrapper
|
||
mut t := tmux.new(sessionid: args.name)!
|
||
|
||
return Container{
|
||
name: args.name
|
||
node: h.node
|
||
tmux: t
|
||
}
|
||
}
|
||
|
||
pub fn (h HetznerBackend) get_info() !NodeInfo {
|
||
return NodeInfo{
|
||
ip: h.node.settings.node_ip
|
||
user: h.node.settings.user
|
||
provider: 'hetzner'
|
||
status: 'connected'
|
||
}
|
||
}
|
||
|
||
// Internal helper to create container
|
||
fn (h HetznerBackend) create_container(name string) ! {
|
||
ver := '3.20.3'
|
||
file := 'alpine-minirootfs-${ver}-x86_64.tar.gz'
|
||
url := 'https://dl-cdn.alpinelinux.org/alpine/v${ver[..4]}/releases/x86_64/${file}'
|
||
|
||
setup_cmd := '
|
||
mkdir -p /containers/${name}/rootfs &&
|
||
cd /containers/${name}/rootfs &&
|
||
echo "📥 Downloading Alpine rootfs: ${url}" &&
|
||
curl -fSL ${url} | tar -xzf - &&
|
||
cd /containers/${name} &&
|
||
rm -f config.json &&
|
||
runc spec
|
||
'
|
||
|
||
remote_cmd := 'ssh ${h.node.settings.user}@${h.node.settings.node_ip} "${setup_cmd}"'
|
||
stream_command(remote_cmd)!
|
||
|
||
console.print_green('Container ${name} rootfs prepared')
|
||
}
|
||
|
||
// Helper function for streaming commands
|
||
fn stream_command(cmd string) ! {
|
||
console.print_debug_title('Executing', cmd)
|
||
code := os.system(cmd)
|
||
if code != 0 {
|
||
console.print_stderr('Command failed: ${cmd} (exit ${code})')
|
||
return error('command failed: ${cmd} (exit ${code})')
|
||
}
|
||
}
|