This commit is contained in:
2025-08-28 13:28:05 +02:00
parent 60fd795b1f
commit 12c197207c
9 changed files with 146 additions and 96 deletions

1
examples/virt/hetzner/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
hetzner_example

View File

@@ -45,17 +45,20 @@ println(serverinfo)
// cl.server_reset(name:"kristof2",wait:true)!
cl.server_rescue(name:"kristof2",wait:true, hero_install:true,sshkey_name:"kristof")!
//don't forget to specify the keyname needed
// cl.server_rescue(name:"kristof2",wait:true, hero_install:true,sshkey_name:"kristof")!
mut ks:=cl.keys_get()!
println(ks)
// mut ks:=cl.keys_get()!
// println(ks)
console.print_header('SSH login')
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
// console.print_header('SSH login')
// mut b := builder.new()!
// mut n := b.node_new(ipaddr: serverinfo.server_ip)!
//this will put hero in debug mode on the system
n.hero_install(compile:true)!
// n.hero_install(compile:true)!
// n.shell("")!
cl.ubuntu_install(name:"kristof2",wait:true, hero_install:true,sshkey_name:"kristof")!

View File

@@ -59,7 +59,7 @@ pub fn (mut node Node) hero_install(args HeroInstallArgs) ! {
mut todo := []string{}
if ! args.compile {
todo << "curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_herolib.sh > /tmp/install.sh"
todo << "curl https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_hero.sh > /tmp/install.sh"
todo << "bash /tmp/install.sh"
}else{
todo << "curl 'https://raw.githubusercontent.com/freeflowuniverse/herolib/refs/heads/development/install_v.sh' > /tmp/install_v.sh"

View File

@@ -7,6 +7,7 @@ import freeflowuniverse.herolib.osal.rsync
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.data.ipaddress
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.texttools
@[heap]
pub struct ExecutorSSH {
@@ -52,7 +53,16 @@ pub fn (mut executor ExecutorSSH) exec(args_ ExecArgs) !string {
if executor.ipaddr.port > 10 {
port = '-p ${executor.ipaddr.port}'
}
if args.cmd.contains("\n"){
//need to upload the file first
args.cmd = texttools.dedent(args.cmd)
executor.file_write('/tmp/toexec.sh', args.cmd)!
args.cmd = "bash /tmp/toexec.sh"
}
args.cmd = 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${executor.user}@${executor.ipaddr.addr} ${port} "${args.cmd}"'
res := osal.exec(cmd: args.cmd, stdout: args.stdout, debug: executor.debug)!
return res.output
}
@@ -63,7 +73,15 @@ pub fn (mut executor ExecutorSSH) exec_interactive(args_ ExecArgs) ! {
if executor.ipaddr.port > 10 {
port = '-p ${executor.ipaddr.port}'
}
if args.cmd.contains("\n"){
args.cmd = texttools.dedent(args.cmd)
//need to upload the file first
executor.file_write('/tmp/toexec.sh', args.cmd)!
args.cmd = "bash /tmp/toexec.sh"
}
args.cmd = 'ssh -tt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${executor.user}@${executor.ipaddr.addr} ${port} "${args.cmd}"'
console.print_debug(args.cmd)
osal.execute_interactive(args.cmd)!
}

View File

@@ -70,6 +70,49 @@ pub fn ping(args PingArgs) !PingResult {
return .ok
}
@[params]
pub struct RebootWaitArgs {
pub mut:
address string @[required] // 192.168.8.8
timeout_down i64 = 2 // total time in seconds to wait till its down
timeout_up i64 = 60 * 5
}
// test if a tcp port answers
//```
// address string //192.168.8.8
// port int = 22
// timeout u16 = 2000 // total time in milliseconds to keep on trying
//```
pub fn reboot_wait(args RebootWaitArgs) ! {
start_time := time.now().unix_milli()
mut run_time := 0.0
for true {
console.print_debug("Waiting for server to go down...")
run_time = time.now().unix_milli()
if run_time > start_time + args.timeout_down {
return error("timeout in waiting for server down")
}
if ping(address:args.address)! == .timeout {
break
}
time.sleep(1)
}
for true {
console.print_debug("Waiting for server to come back up...")
run_time = time.now().unix_milli()
if run_time > start_time + args.timeout_up {
return error("timeout in waiting for server up")
}
if ping(address:args.address)! == .ok {
break
}
time.sleep(1)
}
}
@[params]
pub struct TcpPortTestArgs {
pub mut:

View File

@@ -1,63 +0,0 @@
module hetznermanager
// TODO: couldn't get ssh lib to work
// pub fn (h HetznerManager) server_prepare(name string) !bool {
// srvs := h.servers_list()!
// // console.print_debug(srvs)
// mut srvid := 0
// mut srvip := ""
// for s in srvs {
// if s.server.server_name == name {
// // console.print_debug(s)
// srvid = s.server.server_number
// srvip = s.server.server_ip
// }
// }
// if srvid == 0 {
// panic("could not find server")
// }
// console.print_debug("[+] request rescue mode")
// resc := h.server_rescue(srvid)!
// password := resc.rescue.password
// console.print_debug("[+] rescue password: $password")
// // console.print_debug(resc)
// console.print_debug("[+] fetching server information")
// boot := h.server_boot(srvid)!
// // console.print_debug(boot)
// console.print_debug("[+] forcing reboot")
// reset := h.server_reset(srvid)!
// // console.print_debug(reset)
// time.sleep(30000 * time.millisecond)
// console.print_debug("[+] waiting for rescue to be ready")
// for {
// target := vssh.new(srvip, 22) or {
// console.print_debug("$err")
// time.sleep(30000 * time.millisecond)
// continue
// }
// // rescue doesn't support keyboard-interactive, fallback to password
// target.authenticate(.password, "root", password)!
// check := target.execute("grep 'Hetzner Rescue System.' /etc/motd")!
// if check.exitcode == 0 {
// console.print_debug("[+] we are logged in on the rescue system !")
// // executing deployment binary
// target.upload(os.args[0], "/tmp/deployment")!
// target.stream("stdbuf -i0 -o0 -e0 /tmp/deployment")!
// exit(0)
// }
// }
// return true
// }

View File

@@ -37,18 +37,27 @@ pub fn (mut h HetznerManager) server_rescue(args_ ServerRescueArgs) !ServerInfoD
mut args := args_
mut serverinfo := h.server_info_get(id: args.id, name: args.name)!
console.print_header('server ${serverinfo.server_name} goes into rescue mode')
if serverinfo.rescue && ! args.reset {
if osal.ssh_test(address: serverinfo.server_ip, port: 22)! == .ok {
console.print_debug('test server ${serverinfo.server_name} is in rescue mode?')
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
console.print_debug('server ${serverinfo.server_name} is in rescue mode')
res:=n.exec(cmd:"ls /root/.oldroot/nfs/install/installimage") or {
"ERROR"
}
if res.contains("nfs/install/installimage"){
console.print_debug('server ${serverinfo.server_name} is in rescue mode')
return serverinfo
}
}
serverinfo.rescue = false
}
// only do it if its not in rescue yet
if serverinfo.rescue == false || args.reset {
console.print_header('server ${serverinfo.server_name} goes into rescue mode')
mut keyfps := []string{}
if args.sshkey_name != '' {
keyfps << h.key_get(args.sshkey_name)!.fingerprint
@@ -67,9 +76,9 @@ pub fn (mut h HetznerManager) server_rescue(args_ ServerRescueArgs) !ServerInfoD
dataformat: .urlencoded
)!
console.print_debug('hetzner rescue\n${rescue}')
// console.print_debug('hetzner rescue\n${rescue}')
h.server_reset(id: args.id, name: args.name, wait: args.wait)!
h.server_reset(id: args.id, name: args.name, wait: args.wait, msg:" to get up and running in rescue mode.")!
os.execute_opt("ssh-keygen -R ${serverinfo.server_ip}")!
}
@@ -81,6 +90,7 @@ pub fn (mut h HetznerManager) server_rescue(args_ ServerRescueArgs) !ServerInfoD
if args.wait {
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
n.exec_silent("apt update && apt install -y mc redis")!
if args.hero_install {
n.hero_install()!
}
@@ -94,8 +104,62 @@ pub fn (mut h HetznerManager) server_rescue(args_ ServerRescueArgs) !ServerInfoD
pub fn (mut h HetznerManager) server_rescue_node(args ServerRescueArgs) !&builder.Node {
mut serverinfo := h.server_rescue(args)!
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
return n
}
pub struct ServerInstallArgs {
pub mut:
id int
name string
wait bool = true
hero_install bool
hero_install_compile bool
sshkey_name string @[required]
raid bool
}
pub fn (mut h HetznerManager) ubuntu_install(args ServerInstallArgs) !&builder.Node {
mut serverinfo := h.server_rescue(id:args.id,name:args.name,wait:true,sshkey_name:args.sshkey_name)!
mut b := builder.new()!
mut n := b.node_new(ipaddr: serverinfo.server_ip)!
// installconfig:=$tmpl("templates/ubuntu_install.sh")
// n.file_write("/tmp/installconfig",installconfig)!
// n.exec_interactive("installimage -a -c /tmp/installconfig")!
mut rstr:=""
if args.raid {
rstr="-r yes -l 1 "
}
n.exec_interactive('
set -ex
echo "go into install mode, try to install ubuntu 24.04"
/root/.oldroot/nfs/install/installimage -a -n kristof2 ${rstr} -i /root/.oldroot/nfs/images/Ubuntu-2404-noble-amd64-base.tar.gz -f yes -t yes swap:swap:4G,/boot:ext3:1024M,/:btrfs:all
reboot')!
os.execute_opt("ssh-keygen -R ${serverinfo.server_ip}")!
console.print_debug('server ${serverinfo.server_name} is installed in ubuntu now, should be restarting.')
osal.reboot_wait(
address: serverinfo.server_ip
timeout_down: 60
timeout_up: 60 * 5
)!
if args.hero_install {
n.hero_install(compile: args.hero_install_compile)!
}
return n
}

View File

@@ -21,6 +21,7 @@ pub mut:
id int
name string
wait bool = true
msg string
}
pub fn (mut h HetznerManager) server_reset(args ServerRebootArgs) !ResetInfo {
@@ -45,7 +46,6 @@ pub fn (mut h HetznerManager) server_reset(args ServerRebootArgs) !ResetInfo {
dataformat: .urlencoded
// dict_key:'reset'
)!
println(o)
console.print_debug('server ${serverinfo.server_name} reset done.')
// now need to wait till it goes off
if serveractive {
@@ -64,7 +64,7 @@ pub fn (mut h HetznerManager) server_reset(args ServerRebootArgs) !ResetInfo {
if args.wait {
for {
time.sleep(1000 * time.millisecond)
console.print_debug('wait for ${serverinfo.server_name}')
console.print_debug('wait for ${serverinfo.server_name} ${args.msg}')
if osal.ssh_test(address: serverinfo.server_ip)! == .ok {
console.print_debug('ssh test ok')
console.print_header('server is rebooted: ${serverinfo.server_name}')
@@ -80,19 +80,3 @@ pub fn (mut h HetznerManager) server_reset(args ServerRebootArgs) !ResetInfo {
return o
}
// /////////////////////////////////////BOOT
// struct BootRoot {
// boot Boot
// }
// struct Boot {
// rescue RescueInfo
// }
// pub fn (mut h HetznerManager) server_boot(id int) !RescueInfo {
// mut conn := h.connection()!
// boot := conn.get_json[BootRoot](prefix: 'boot/${id}')!
// return boot.boot.rescue
// }