diff --git a/examples/clients/mycelium.vsh b/examples/clients/mycelium.vsh index ce748573..305e323d 100755 --- a/examples/clients/mycelium.vsh +++ b/examples/clients/mycelium.vsh @@ -1,42 +1,73 @@ #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run import freeflowuniverse.herolib.clients.mycelium +import freeflowuniverse.herolib.installers.net.mycelium as mycelium_installer +import freeflowuniverse.herolib.osal +import time +import os + +// Check if not installed install it. +mut installer := mycelium_installer.get()! +installer.install()! mycelium.delete()! -mut r := mycelium.inspect()! -println('My pub key: ${r.public_key}') +res := os.execute('mkdir -p /tmp/mycelium_server1 && cd /tmp/mycelium_server1 && mycelium --peers tcp://188.40.132.242:9651 quic://[2a01:4f8:212:fa6::2]:9651 tcp://185.69.166.7:9651 quic://[2a02:1802:5e:0:ec4:7aff:fe51:e36b]:9651 tcp://65.21.231.58:9651 quic://[2a01:4f9:5a:1042::2]:9651 tcp://[2604:a00:50:17b:9e6b:ff:fe1f:e054]:9651 quic://5.78.122.16:9651 tcp://[2a01:4ff:2f0:3621::1]:9651 quic://142.93.217.194:9651 --tun-name tun2 --tcp-listen-port 9652 --quic-listen-port 9653 --api-addr 127.0.0.1:9001') +println('res: ${res}') +// spawn fn () { +// res := os.execute('mkdir -p /tmp/mycelium_server1 && cd /tmp/mycelium_server1 && mycelium --peers tcp://188.40.132.242:9651 quic://[2a01:4f8:212:fa6::2]:9651 tcp://185.69.166.7:9651 quic://[2a02:1802:5e:0:ec4:7aff:fe51:e36b]:9651 tcp://65.21.231.58:9651 quic://[2a01:4f9:5a:1042::2]:9651 tcp://[2604:a00:50:17b:9e6b:ff:fe1f:e054]:9651 quic://5.78.122.16:9651 tcp://[2a01:4ff:2f0:3621::1]:9651 quic://142.93.217.194:9651 --tun-name tun2 --tcp-listen-port 9652 --quic-listen-port 9653 --api-addr 127.0.0.1:9001') +// println('res: ${res}') +// }() -mut client := mycelium.get()! -println(client) +spawn fn () { + os.execute('mkdir -p /tmp/mycelium_server2 && cd /tmp/mycelium_server2 && mycelium --peers tcp://188.40.132.242:9651 quic://[2a01:4f8:212:fa6::2]:9651 tcp://185.69.166.7:9651 quic://[2a02:1802:5e:0:ec4:7aff:fe51:e36b]:9651 tcp://65.21.231.58:9651 quic://[2a01:4f9:5a:1042::2]:9651 tcp://[2604:a00:50:17b:9e6b:ff:fe1f:e054]:9651 quic://5.78.122.16:9651 tcp://[2a01:4ff:2f0:3621::1]:9651 quic://142.93.217.194:9651 --tun-name tun3 --tcp-listen-port 9654 --quic-listen-port 9655 --api-addr 127.0.0.1:9002') +}() -// Send a message to a node by public key -// Parameters: public_key, payload, topic, wait_for_reply -msg := client.send_msg( - public_key: '0569a9c54da7a52b2ab3a2fb03f2b9be2c1c11d65d14a4888182bd12ed1dbf38' // destination public key - payload: 'Hello World' // message payload - topic: 'greetings' // optional topic -)! +time.sleep(2 * time.second) -println('Sent message ID: ${msg.id}') -println('send succeeded') +mut client1 := mycelium.get()! +client1.server_url = 'http://localhost:9001' +client1.name = 'client1' +println(client1) -// Receive messages -// Parameters: wait_for_message, peek_only, topic_filter -received := client.receive_msg(wait: true, peek: false, topic: 'greetings')! -println('Received message from: ${received.src_pk}') -println('Message payload: ${received.payload}') +mut client2 := mycelium.get()! +client2.server_url = 'http://localhost:9002' +client2.name = 'client2' +println(client2) -// Reply to a message -client.reply_msg( - id: received.id - public_key: received.src_pk - payload: 'Got your message!' - topic: 'greetings' -)! +inspect1 := mycelium.inspect(key_file_path: '/tmp/mycelium_server1/priv_key.bin')! +inspect2 := mycelium.inspect(key_file_path: '/tmp/mycelium_server2/priv_key.bin')! -// Check message status -status := client.get_msg_status(msg.id)! -println('Message status: ${status.state}') -println('Created at: ${status.created}') -println('Expires at: ${status.deadline}') +println('Server 1 public key: ${inspect1.public_key}') +println('Server 2 public key: ${inspect2.public_key}') + +// // Send a message to a node by public key +// // Parameters: public_key, payload, topic, wait_for_reply +// msg := client.send_msg( +// public_key: '0569a9c54da7a52b2ab3a2fb03f2b9be2c1c11d65d14a4888182bd12ed1dbf38' // destination public key +// payload: 'Hello World' // message payload +// topic: 'greetings' // optional topic +// )! + +// println('Sent message ID: ${msg.id}') +// println('send succeeded') + +// // Receive messages +// // Parameters: wait_for_message, peek_only, topic_filter +// received := client.receive_msg(wait: true, peek: false, topic: 'greetings')! +// println('Received message from: ${received.src_pk}') +// println('Message payload: ${received.payload}') + +// // Reply to a message +// client.reply_msg( +// id: received.id +// public_key: received.src_pk +// payload: 'Got your message!' +// topic: 'greetings' +// )! + +// // Check message status +// status := client.get_msg_status(msg.id)! +// println('Message status: ${status.state}') +// println('Created at: ${status.created}') +// println('Expires at: ${status.deadline}') diff --git a/examples/installers/coredns.vsh b/examples/installers/coredns.vsh index aa4bd9fe..2bc22432 100755 --- a/examples/installers/coredns.vsh +++ b/examples/installers/coredns.vsh @@ -4,6 +4,5 @@ import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer import freeflowuniverse.herolib.osal // coredns_installer.delete()! -mut installer:= coredns_installer.get()! +mut installer := coredns_installer.get()! installer.build()! - diff --git a/examples/installers/traefik.vsh b/examples/installers/traefik.vsh index 47af5179..dfc99220 100755 --- a/examples/installers/traefik.vsh +++ b/examples/installers/traefik.vsh @@ -1,13 +1,12 @@ #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run -import os +import os import freeflowuniverse.herolib.installers.web.traefik as traefik_installer - traefik_installer.delete()! -mut installer:= traefik_installer.get()! +mut installer := traefik_installer.get()! -installer.password = "planet" +installer.password = 'planet' traefik_installer.set(installer)! installer.start()! diff --git a/lib/clients/mycelium/mycelium_check.v b/lib/clients/mycelium/mycelium_check.v index 4177bf66..4bbb6330 100644 --- a/lib/clients/mycelium/mycelium_check.v +++ b/lib/clients/mycelium/mycelium_check.v @@ -43,15 +43,24 @@ pub: address string } -pub fn inspect() !MyceliumInspectResult { - command := 'mycelium inspect --key-file /root/hero/cfg/priv_key.bin --json' +@[params] +pub struct MyceliumInspectArgs { +pub: + key_file_path string = '/root/hero/cfg/priv_key.bin' +} + +pub fn inspect(args MyceliumInspectArgs) !MyceliumInspectResult { + command := 'mycelium inspect --key-file ${args.key_file_path} --json' result := os.execute(command) + if result.exit_code != 0 { return error('Command failed: ${result.output}') } + inspect_result := json.decode(MyceliumInspectResult, result.output) or { return error('Failed to parse JSON: ${err}') } + return inspect_result } diff --git a/lib/installers/infra/coredns/coredns_actions.v b/lib/installers/infra/coredns/coredns_actions.v index 5b987a7e..724c52ed 100644 --- a/lib/installers/infra/coredns/coredns_actions.v +++ b/lib/installers/infra/coredns/coredns_actions.v @@ -10,174 +10,171 @@ import freeflowuniverse.herolib.osal.zinit import freeflowuniverse.herolib.installers.ulist import freeflowuniverse.herolib.core.httpconnection import freeflowuniverse.herolib.installers.lang.golang - - import os -fn startupcmd () ![]zinit.ZProcessNewArgs{ - mut args := get()! - mut res := []zinit.ZProcessNewArgs{} - cmd := "coredns -conf '${args.config_path}'" - res << zinit.ZProcessNewArgs{ - name: 'coredns' - cmd: cmd - } - return res - +fn startupcmd() ![]zinit.ZProcessNewArgs { + mut args := get()! + mut res := []zinit.ZProcessNewArgs{} + cmd := "coredns -conf '${args.config_path}'" + res << zinit.ZProcessNewArgs{ + name: 'coredns' + cmd: cmd + } + return res } fn running() !bool { - mut installer := get()! + mut installer := get()! mut conn := httpconnection.new(name: 'coredns', url: 'http://localhost:3334')! r := conn.get(prefix: 'health')! if r.trim_space() == 'OK' { return true } return false - } -fn start_pre()!{ - fix()! +fn start_pre() ! { + fix()! } -fn start_post()!{ - set_local_dns() +fn start_post() ! { + set_local_dns() } -fn stop_pre()!{ - +fn stop_pre() ! { } -fn stop_post()!{ - +fn stop_post() ! { } - //////////////////// following actions are not specific to instance of the object // checks if a certain version or above is installed fn installed() !bool { - res := os.execute('${osal.profile_path_source_and()!} coredns version') - if res.exit_code != 0 { - return false - } - r := res.output.split_into_lines().filter(it.trim_space().starts_with('CoreDNS-')) - if r.len != 1 { - return error("couldn't parse coredns version.\n${res.output}") - } - if texttools.version(version) == texttools.version(r[0].all_after_first('CoreDNS-')) { - return true - } - return false + res := os.execute('${osal.profile_path_source_and()!} coredns version') + if res.exit_code != 0 { + return false + } + r := res.output.split_into_lines().filter(it.trim_space().starts_with('CoreDNS-')) + if r.len != 1 { + return error("couldn't parse coredns version.\n${res.output}") + } + if texttools.version(version) == texttools.version(r[0].all_after_first('CoreDNS-')) { + return true + } + return false } -//get the Upload List of the files +// get the Upload List of the files fn ulist_get() !ulist.UList { - //optionally build a UList which is all paths which are result of building, is then used e.g. in upload - return ulist.UList{} + // optionally build a UList which is all paths which are result of building, is then used e.g. in upload + return ulist.UList{} } -//uploads to S3 server if configured +// uploads to S3 server if configured fn upload() ! { - // installers.upload( - // cmdname: 'coredns' - // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/coredns' - // )! - + // installers.upload( + // cmdname: 'coredns' + // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/coredns' + // )! } fn install() ! { - console.print_header('install coredns') - mut url := '' - if core.is_linux_arm()! { - url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_linux_arm64.tgz' - } else if core.is_linux_intel()! { - url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_linux_amd64.tgz' - } else if core.is_osx_arm()! { - url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_darwin_arm64.tgz' - } else if core.is_osx_intel()! { - url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_darwin_amd64.tgz' - } else { - return error('unsported platform') - } + console.print_header('install coredns') + build()! // because we need the plugins + // mut url := '' + // if core.is_linux_arm()! { + // url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_linux_arm64.tgz' + // } else if core.is_linux_intel()! { + // url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_linux_amd64.tgz' + // } else if core.is_osx_arm()! { + // url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_darwin_arm64.tgz' + // } else if core.is_osx_intel()! { + // url = 'https://github.com/coredns/coredns/releases/download/v${version}/coredns_${version}_darwin_amd64.tgz' + // } else { + // return error('unsported platform') + // } - mut dest := osal.download( - url: url - minsize_kb: 13000 - expand_dir: '/tmp/coredns' - )! + // mut dest := osal.download( + // url: url + // minsize_kb: 13000 + // expand_dir: '/tmp/coredns' + // )! - mut binpath := dest.file_get('coredns')! - osal.cmd_add( - cmdname: 'coredns' - source: binpath.path - )! + // mut binpath := dest.file_get('coredns')! + // osal.cmd_add( + // cmdname: 'coredns' + // source: binpath.path + // )! } fn build() ! { - url := 'https://github.com/coredns/coredns' + url := 'https://github.com/coredns/coredns' - if core.platform()! != .ubuntu { - return error('only support ubuntu for now') - } - mut g:=golang.get()! - g.install()! + if core.platform()! != .ubuntu { + return error('only support ubuntu for now') + } + mut g := golang.get()! + g.install()! - console.print_header('build coredns') + console.print_header('build coredns') - mut gs := gittools.new(coderoot: '~/code')! + mut gs := gittools.new()! - gitpath := gs.get_repo(url: url, reset: true, pull: true)! + gitpath := gs.get_path( + pull: true + reset: true + url: url + )! - cmd := ' + // set the plugins file on right location + pluginsfile := $tmpl('templates/plugin.cfg') + mut path := pathlib.get_file(path: '${gitpath}/plugin.cfg', create: true)! + path.write(pluginsfile)! + + cmd := ' cd ${gitpath} make ' - osal.execute_stdout(cmd)! - - //now copy to the default bin path - // mut binpath := dest.file_get('...')! - // adds it to path - // osal.cmd_add( - // cmdname: 'griddriver2' - // source: binpath.path - // )! + osal.execute_stdout(cmd)! + // now copy to the default bin path + mut codedir := pathlib.get_dir(path: '${gitpath}', create: false)! + mut binpath := codedir.file_get('coredns')! + osal.cmd_add( + cmdname: 'coredns' + source: binpath.path + )! } fn destroy() ! { + // mut systemdfactory := systemd.new()! + // systemdfactory.destroy("zinit")! - // mut systemdfactory := systemd.new()! - // systemdfactory.destroy("zinit")! + // osal.process_kill_recursive(name:'zinit')! + // osal.cmd_delete('zinit')! - // osal.process_kill_recursive(name:'zinit')! - // osal.cmd_delete('zinit')! - - // osal.package_remove(' - // podman - // conmon - // buildah - // skopeo - // runc - // ')! - - // //will remove all paths where go/bin is found - // osal.profile_path_add_remove(paths2delete:"go/bin")! - - // osal.rm(" - // podman - // conmon - // buildah - // skopeo - // runc - // /var/lib/containers - // /var/lib/podman - // /var/lib/buildah - // /tmp/podman - // /tmp/conmon - // ")! + // osal.package_remove(' + // podman + // conmon + // buildah + // skopeo + // runc + // ')! + // //will remove all paths where go/bin is found + // osal.profile_path_add_remove(paths2delete:"go/bin")! + // osal.rm(" + // podman + // conmon + // buildah + // skopeo + // runc + // /var/lib/containers + // /var/lib/podman + // /var/lib/buildah + // /tmp/podman + // /tmp/conmon + // ")! } - diff --git a/lib/installers/infra/coredns/coredns_configure.v b/lib/installers/infra/coredns/coredns_configure.v index 5aa053e2..15e30f28 100644 --- a/lib/installers/infra/coredns/coredns_configure.v +++ b/lib/installers/infra/coredns/coredns_configure.v @@ -12,7 +12,6 @@ pub fn configure() ! { set_global_dns() - if args.config_url.len > 0 { mut repo := gs.get_repo( url: args.config_url @@ -42,17 +41,15 @@ pub fn configure() ! { mut path := pathlib.get_file(path: args.config_path, create: true)! path.write(mycorefile)! - if args.example{ - example_configure() ! + if args.example { + example_configure()! } - } pub fn example_configure() ! { mut args := get()! - myipaddr:=osal.ipaddr_pub_get()! - + myipaddr := osal.ipaddr_pub_get_check()! exampledbfile := $tmpl('templates/ourexample.org') diff --git a/lib/installers/infra/coredns/coredns_factory_.v b/lib/installers/infra/coredns/coredns_factory_.v index d39772bf..4ece5417 100644 --- a/lib/installers/infra/coredns/coredns_factory_.v +++ b/lib/installers/infra/coredns/coredns_factory_.v @@ -4,288 +4,277 @@ import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.data.paramsparser - import freeflowuniverse.herolib.sysadmin.startupmanager import freeflowuniverse.herolib.osal.zinit import time __global ( - coredns_global map[string]&CoreDNS - coredns_default string + coredns_global map[string]&CoreDNS + coredns_default string ) /////////FACTORY @[params] -pub struct ArgsGet{ +pub struct ArgsGet { pub mut: - name string + name string } -fn args_get (args_ ArgsGet) ArgsGet { - mut args:=args_ - if args.name == ""{ - args.name = "default" - } - return args +fn args_get(args_ ArgsGet) ArgsGet { + mut args := args_ + if args.name == '' { + args.name = 'default' + } + return args } -pub fn get(args_ ArgsGet) !&CoreDNS { - mut context:=base.context()! - mut args := args_get(args_) - mut obj := CoreDNS{} - if !(args.name in coredns_global) { - if ! exists(args)!{ - set(obj)! - }else{ - heroscript := context.hero_config_get("coredns",args.name)! - mut obj_:=heroscript_loads(heroscript)! - set_in_mem(obj_)! - } - } - return coredns_global[args.name] or { - println(coredns_global) - //bug if we get here because should be in globals - panic("could not get config for coredns with name, is bug:${args.name}") - } +pub fn get(args_ ArgsGet) !&CoreDNS { + mut context := base.context()! + mut args := args_get(args_) + mut obj := CoreDNS{} + if args.name !in coredns_global { + if !exists(args)! { + set(obj)! + } else { + heroscript := context.hero_config_get('coredns', args.name)! + mut obj_ := heroscript_loads(heroscript)! + set_in_mem(obj_)! + } + } + return coredns_global[args.name] or { + println(coredns_global) + // bug if we get here because should be in globals + panic('could not get config for coredns with name, is bug:${args.name}') + } } -//register the config for the future -pub fn set(o CoreDNS)! { - set_in_mem(o)! - mut context := base.context()! - heroscript := heroscript_dumps(o)! - context.hero_config_set("coredns", o.name, heroscript)! +// register the config for the future +pub fn set(o CoreDNS) ! { + set_in_mem(o)! + mut context := base.context()! + heroscript := heroscript_dumps(o)! + context.hero_config_set('coredns', o.name, heroscript)! } -//does the config exists? -pub fn exists(args_ ArgsGet)! bool { - mut context := base.context()! - mut args := args_get(args_) - return context.hero_config_exists("coredns", args.name) +// does the config exists? +pub fn exists(args_ ArgsGet) !bool { + mut context := base.context()! + mut args := args_get(args_) + return context.hero_config_exists('coredns', args.name) } -pub fn delete(args_ ArgsGet)! { - mut args := args_get(args_) - mut context:=base.context()! - context.hero_config_delete("coredns",args.name)! - if args.name in coredns_global { - //del coredns_global[args.name] - } +pub fn delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context := base.context()! + context.hero_config_delete('coredns', args.name)! + if args.name in coredns_global { + // del coredns_global[args.name] + } } -//only sets in mem, does not set as config -fn set_in_mem(o CoreDNS)! { - mut o2:=obj_init(o)! - coredns_global[o.name] = &o2 - coredns_default = o.name +// only sets in mem, does not set as config +fn set_in_mem(o CoreDNS) ! { + mut o2 := obj_init(o)! + coredns_global[o.name] = &o2 + coredns_default = o.name } - @[params] pub struct PlayArgs { pub mut: - heroscript string //if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool + heroscript string // if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - - mut args:=args_ + mut args := args_ + mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } - mut plbook := args.plbook or { - playbook.new(text: args.heroscript)! - } - - mut install_actions := plbook.find(filter: 'coredns.configure')! - if install_actions.len > 0 { - for install_action in install_actions { - heroscript:=install_action.heroscript() - mut obj2:=heroscript_loads(heroscript)! - set(obj2)! - } - } + mut install_actions := plbook.find(filter: 'coredns.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + } + } - mut other_actions := plbook.find(filter: 'coredns.')! - for other_action in other_actions { - if other_action.name in ["destroy","install","build"]{ - mut p := other_action.params - reset:=p.get_default_false("reset") - if other_action.name == "destroy" || reset{ - console.print_debug("install action coredns.destroy") - destroy()! - } - if other_action.name == "install"{ - console.print_debug("install action coredns.install") - install()! - } - } - if other_action.name in ["start","stop","restart"]{ - mut p := other_action.params - name := p.get('name')! - mut coredns_obj:=get(name:name)! - console.print_debug("action object:\n${coredns_obj}") - if other_action.name == "start"{ - console.print_debug("install action coredns.${other_action.name}") - coredns_obj.start()! - } - - if other_action.name == "stop"{ - console.print_debug("install action coredns.${other_action.name}") - coredns_obj.stop()! - } - if other_action.name == "restart"{ - console.print_debug("install action coredns.${other_action.name}") - coredns_obj.restart()! - } - } - } + mut other_actions := plbook.find(filter: 'coredns.')! + for other_action in other_actions { + if other_action.name in ['destroy', 'install', 'build'] { + mut p := other_action.params + reset := p.get_default_false('reset') + if other_action.name == 'destroy' || reset { + console.print_debug('install action coredns.destroy') + destroy()! + } + if other_action.name == 'install' { + console.print_debug('install action coredns.install') + install()! + } + } + if other_action.name in ['start', 'stop', 'restart'] { + mut p := other_action.params + name := p.get('name')! + mut coredns_obj := get(name: name)! + console.print_debug('action object:\n${coredns_obj}') + if other_action.name == 'start' { + console.print_debug('install action coredns.${other_action.name}') + coredns_obj.start()! + } + if other_action.name == 'stop' { + console.print_debug('install action coredns.${other_action.name}') + coredns_obj.stop()! + } + if other_action.name == 'restart' { + console.print_debug('install action coredns.${other_action.name}') + coredns_obj.restart()! + } + } + } } - //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager { - // unknown - // screen - // zinit - // tmux - // systemd - match cat{ - .zinit{ - console.print_debug("startupmanager: zinit") - return startupmanager.get(cat:.zinit)! - } - .systemd{ - console.print_debug("startupmanager: systemd") - return startupmanager.get(cat:.systemd)! - }else{ - console.print_debug("startupmanager: auto") - return startupmanager.get()! - } - } + // unknown + // screen + // zinit + // tmux + // systemd + match cat { + .zinit { + console.print_debug('startupmanager: zinit') + return startupmanager.get(cat: .zinit)! + } + .systemd { + console.print_debug('startupmanager: systemd') + return startupmanager.get(cat: .systemd)! + } + else { + console.print_debug('startupmanager: auto') + return startupmanager.get()! + } + } } -//load from disk and make sure is properly intialized +// load from disk and make sure is properly intialized pub fn (mut self CoreDNS) reload() ! { - switch(self.name) - self=obj_init(self)! + switch(self.name) + self = obj_init(self)! } pub fn (mut self CoreDNS) start() ! { - switch(self.name) - if self.running()!{ - return - } + switch(self.name) + if self.running()! { + return + } - console.print_header('coredns start') + console.print_header('coredns start') - if ! installed()!{ - install()! - } + if !installed()! { + install()! + } - configure()! + configure()! - start_pre()! + start_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! - console.print_debug('starting coredns with ${zprocess.startuptype}...') + console.print_debug('starting coredns with ${zprocess.startuptype}...') - sm.new(zprocess)! + sm.new(zprocess)! - sm.start(zprocess.name)! - } + sm.start(zprocess.name)! + } - start_post()! - - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('coredns did not install properly.') + start_post()! + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('coredns did not install properly.') } pub fn (mut self CoreDNS) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! + switch(self.name) + self.install(args)! + self.start()! } pub fn (mut self CoreDNS) stop() ! { - switch(self.name) - stop_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - sm.stop(zprocess.name)! - } - stop_post()! + switch(self.name) + stop_pre()! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + sm.stop(zprocess.name)! + } + stop_post()! } pub fn (mut self CoreDNS) restart() ! { - switch(self.name) - self.stop()! - self.start()! + switch(self.name) + self.stop()! + self.start()! } pub fn (mut self CoreDNS) running() !bool { - switch(self.name) + switch(self.name) - //walk over the generic processes, if not running return - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - r:=sm.running(zprocess.name)! - if r==false{ - return false - } - } - return running()! + // walk over the generic processes, if not running return + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + r := sm.running(zprocess.name)! + if r == false { + return false + } + } + return running()! } @[params] -pub struct InstallArgs{ +pub struct InstallArgs { pub mut: - reset bool + reset bool } pub fn (mut self CoreDNS) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } + switch(self.name) + if args.reset || (!installed()!) { + install()! + } } pub fn (mut self CoreDNS) build() ! { - switch(self.name) - build()! + switch(self.name) + build()! } pub fn (mut self CoreDNS) destroy() ! { - switch(self.name) - self.stop() or {} - destroy()! + switch(self.name) + self.stop() or {} + destroy()! } - - -//switch instance to be used for coredns +// switch instance to be used for coredns pub fn switch(name string) { - coredns_default = name + coredns_default = name } - -//helpers +// helpers @[params] -pub struct DefaultConfigArgs{ - instance string = 'default' +pub struct DefaultConfigArgs { + instance string = 'default' } diff --git a/lib/installers/infra/coredns/coredns_fix.v b/lib/installers/infra/coredns/coredns_fix.v index 3544ec50..f1856954 100644 --- a/lib/installers/infra/coredns/coredns_fix.v +++ b/lib/installers/infra/coredns/coredns_fix.v @@ -5,58 +5,58 @@ import net import freeflowuniverse.herolib.ui.console fn is_systemd_resolved_active() bool { - result := os.execute('systemctl is-active systemd-resolved') - return result.exit_code == 0 && result.output.trim_space() == 'active' + result := os.execute('systemctl is-active systemd-resolved') + return result.exit_code == 0 && result.output.trim_space() == 'active' } fn disable_systemd_resolved() { - console.print_debug('Stopping and disabling systemd-resolved...') - os.execute('sudo systemctl stop systemd-resolved') - os.execute('sudo systemctl disable systemd-resolved') - os.execute('sudo systemctl mask systemd-resolved') + console.print_debug('Stopping and disabling systemd-resolved...') + os.execute('sudo systemctl stop systemd-resolved') + os.execute('sudo systemctl disable systemd-resolved') + os.execute('sudo systemctl mask systemd-resolved') } fn is_dns_port_free() bool { - result := os.execute("sudo ss -tunlp | grep ':53 '") - return result.exit_code != 0 + result := os.execute("sudo ss -tunlp | grep ':53 '") + return result.exit_code != 0 } fn set_local_dns() { - console.print_debug('Updating /etc/resolv.conf to use local DNS...') - os.execute('sudo rm -f /etc/resolv.conf') - os.write_file('/etc/resolv.conf', 'nameserver 127.0.0.1\n') or { - console.print_debug('Failed to update /etc/resolv.conf') - return - } - console.print_debug('/etc/resolv.conf updated successfully.') + console.print_debug('Updating /etc/resolv.conf to use local DNS...') + os.execute('sudo rm -f /etc/resolv.conf') + os.write_file('/etc/resolv.conf', 'nameserver 127.0.0.1\n') or { + console.print_debug('Failed to update /etc/resolv.conf') + return + } + console.print_debug('/etc/resolv.conf updated successfully.') } fn set_global_dns() { - console.print_debug('Updating /etc/resolv.conf to use local DNS...') - os.execute('sudo rm -f /etc/resolv.conf') - os.write_file('/etc/resolv.conf', 'nameserver 8.8.8.8\n') or { - console.print_debug('Failed to update /etc/resolv.conf') - return - } - console.print_debug('/etc/resolv.conf updated successfully for global.') + console.print_debug('Updating /etc/resolv.conf to use local DNS...') + os.execute('sudo rm -f /etc/resolv.conf') + os.write_file('/etc/resolv.conf', 'nameserver 8.8.8.8\n') or { + console.print_debug('Failed to update /etc/resolv.conf') + return + } + console.print_debug('/etc/resolv.conf updated successfully for global.') } -pub fn fix()! { - console.print_debug('Checking if systemd-resolved is active...') - if is_systemd_resolved_active() { - disable_systemd_resolved() - } else { - println('systemd-resolved is already disabled.') - } +pub fn fix() ! { + console.print_debug('Checking if systemd-resolved is active...') + if is_systemd_resolved_active() { + disable_systemd_resolved() + } else { + println('systemd-resolved is already disabled.') + } - console.print_debug('Checking if DNS UDP port 53 is free...') - if is_dns_port_free() { - console.print_debug('UDP port 53 is free.') - } else { - console.print_debug('UDP port 53 is still in use. Ensure CoreDNS or another service is properly set up.') - return - } + console.print_debug('Checking if DNS UDP port 53 is free...') + if is_dns_port_free() { + console.print_debug('UDP port 53 is free.') + } else { + console.print_debug('UDP port 53 is still in use. Ensure CoreDNS or another service is properly set up.') + return + } - set_global_dns() - console.print_debug('Setup complete. Ensure CoreDNS is running.') + set_global_dns() + console.print_debug('Setup complete. Ensure CoreDNS is running.') } diff --git a/lib/installers/infra/coredns/coredns_model.v b/lib/installers/infra/coredns/coredns_model.v index d0147287..7532f348 100644 --- a/lib/installers/infra/coredns/coredns_model.v +++ b/lib/installers/infra/coredns/coredns_model.v @@ -1,4 +1,5 @@ module coredns + import freeflowuniverse.herolib.data.paramsparser import freeflowuniverse.herolib.data.encoderhero import os @@ -7,36 +8,32 @@ pub const version = '1.12.0' const singleton = true const default = true -//THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED +// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED @[heap] pub struct CoreDNS { pub mut: - name string = 'default' - config_path string - config_url string // path to Corefile through e.g. git url, will pull it if it is not local yet - dnszones_path string // path to where all the dns zones are - dnszones_url string // path on git url pull if needed (is comma or \n separated list) + name string = 'default' + config_path string + config_url string // path to Corefile through e.g. git url, will pull it if it is not local yet + dnszones_path string // path to where all the dns zones are + dnszones_url string // path on git url pull if needed (is comma or \n separated list) plugins string // list of plugins to build CoreDNS with (is comma or \n separated list) - example bool = true // if true we will install examples + example bool = true // if true we will install examples } - - -//your checking & initialization code if needed -fn obj_init(mycfg_ CoreDNS)!CoreDNS{ - mut mycfg:=mycfg_ - return mycfg +// your checking & initialization code if needed +fn obj_init(mycfg_ CoreDNS) !CoreDNS { + mut mycfg := mycfg_ + return mycfg } - - /////////////NORMALLY NO NEED TO TOUCH pub fn heroscript_dumps(obj CoreDNS) !string { - return encoderhero.encode[CoreDNS ](obj)! + return encoderhero.encode[CoreDNS](obj)! } pub fn heroscript_loads(heroscript string) !CoreDNS { - mut obj := encoderhero.decode[CoreDNS](heroscript)! - return obj + mut obj := encoderhero.decode[CoreDNS](heroscript)! + return obj } diff --git a/lib/installers/infra/coredns/templates/Corefile b/lib/installers/infra/coredns/templates/Corefile index b9740d8f..24a53989 100644 --- a/lib/installers/infra/coredns/templates/Corefile +++ b/lib/installers/infra/coredns/templates/Corefile @@ -3,7 +3,11 @@ log errors health :3334 - auto ${args.dnszones_path} { - reload 30s - } + redis { + address localhost:6379 + connect_timeout 100 + read_timeout 100 + ttl 360 + prefix dns: + } } diff --git a/lib/installers/infra/coredns/templates/plugin.cfg b/lib/installers/infra/coredns/templates/plugin.cfg new file mode 100644 index 00000000..3f72ac1a --- /dev/null +++ b/lib/installers/infra/coredns/templates/plugin.cfg @@ -0,0 +1,68 @@ +# Directives are registered in the order they should be executed. +# +# Ordering is VERY important. Every plugin will feel the effects of all other +# plugin below (after) them during a request, but they must not care what plugin +# above them are doing. + +# How to rebuild with updated plugin configurations: Modify the list below and +# run `go generate && go build` + +# The parser takes the input format of: +# +# : +# Or +# : +# +# External plugin example: +# +# log:github.com/coredns/coredns/plugin/log +# Local plugin example: +# log:log +#etcd:etcd + +root:root +metadata:metadata +geoip:geoip +cancel:cancel +tls:tls +timeouts:timeouts +multisocket:multisocket +reload:reload +nsid:nsid +bufsize:bufsize +bind:bind +debug:debug +trace:trace +ready:ready +health:health +pprof:pprof +prometheus:metrics +errors:errors +log:log +dnstap:dnstap +local:local +dns64:dns64 +acl:acl +any:any +chaos:chaos +loadbalance:loadbalance +tsig:tsig +cache:cache +rewrite:rewrite +header:header +dnssec:dnssec +autopath:autopath +minimal:minimal +template:template +transfer:transfer +hosts:hosts +file:file +secondary:secondary +loop:loop +forward:forward +erratic:erratic +whoami:whoami +on:github.com/coredns/caddy/onevent +sign:sign +view:view +redis:github.com/codysnider/coredns-redis diff --git a/lib/installers/net/mycelium/mycelium_factory_.v b/lib/installers/net/mycelium/mycelium_factory_.v index fefa2188..3030a224 100644 --- a/lib/installers/net/mycelium/mycelium_factory_.v +++ b/lib/installers/net/mycelium/mycelium_factory_.v @@ -4,288 +4,277 @@ import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.data.paramsparser - import freeflowuniverse.herolib.sysadmin.startupmanager import freeflowuniverse.herolib.osal.zinit import time __global ( - mycelium_global map[string]&MyceliumInstaller - mycelium_default string + mycelium_installer_global map[string]&MyceliumInstaller + mycelium_installer_default string ) /////////FACTORY @[params] -pub struct ArgsGet{ +pub struct ArgsGet { pub mut: - name string + name string } -fn args_get (args_ ArgsGet) ArgsGet { - mut args:=args_ - if args.name == ""{ - args.name = "default" - } - return args +fn args_get(args_ ArgsGet) ArgsGet { + mut args := args_ + if args.name == '' { + args.name = 'default' + } + return args } -pub fn get(args_ ArgsGet) !&MyceliumInstaller { - mut context:=base.context()! - mut args := args_get(args_) - mut obj := MyceliumInstaller{} - if !(args.name in mycelium_global) { - if ! exists(args)!{ - set(obj)! - }else{ - heroscript := context.hero_config_get("mycelium",args.name)! - mut obj_:=heroscript_loads(heroscript)! - set_in_mem(obj_)! - } - } - return mycelium_global[args.name] or { - println(mycelium_global) - //bug if we get here because should be in globals - panic("could not get config for mycelium with name, is bug:${args.name}") - } +pub fn get(args_ ArgsGet) !&MyceliumInstaller { + mut context := base.context()! + mut args := args_get(args_) + mut obj := MyceliumInstaller{} + if args.name !in mycelium_installer_global { + if !exists(args)! { + set(obj)! + } else { + heroscript := context.hero_config_get('mycelium', args.name)! + mut obj_ := heroscript_loads(heroscript)! + set_in_mem(obj_)! + } + } + return mycelium_installer_global[args.name] or { + println(mycelium_installer_global) + // bug if we get here because should be in globals + panic('could not get config for mycelium with name, is bug:${args.name}') + } } -//register the config for the future -pub fn set(o MyceliumInstaller)! { - set_in_mem(o)! - mut context := base.context()! - heroscript := heroscript_dumps(o)! - context.hero_config_set("mycelium", o.name, heroscript)! +// register the config for the future +pub fn set(o MyceliumInstaller) ! { + set_in_mem(o)! + mut context := base.context()! + heroscript := heroscript_dumps(o)! + context.hero_config_set('mycelium', o.name, heroscript)! } -//does the config exists? -pub fn exists(args_ ArgsGet)! bool { - mut context := base.context()! - mut args := args_get(args_) - return context.hero_config_exists("mycelium", args.name) +// does the config exists? +pub fn exists(args_ ArgsGet) !bool { + mut context := base.context()! + mut args := args_get(args_) + return context.hero_config_exists('mycelium', args.name) } -pub fn delete(args_ ArgsGet)! { - mut args := args_get(args_) - mut context:=base.context()! - context.hero_config_delete("mycelium",args.name)! - if args.name in mycelium_global { - //del mycelium_global[args.name] - } +pub fn delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context := base.context()! + context.hero_config_delete('mycelium', args.name)! + if args.name in mycelium_installer_global { + // del mycelium_installer_global[args.name] + } } -//only sets in mem, does not set as config -fn set_in_mem(o MyceliumInstaller)! { - mut o2:=obj_init(o)! - mycelium_global[o.name] = &o2 - mycelium_default = o.name +// only sets in mem, does not set as config +fn set_in_mem(o MyceliumInstaller) ! { + mut o2 := obj_init(o)! + mycelium_installer_global[o.name] = &o2 + mycelium_installer_default = o.name } - @[params] pub struct PlayArgs { pub mut: - heroscript string //if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool + heroscript string // if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - - mut args:=args_ + mut args := args_ + mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } - mut plbook := args.plbook or { - playbook.new(text: args.heroscript)! - } - - mut install_actions := plbook.find(filter: 'mycelium.configure')! - if install_actions.len > 0 { - for install_action in install_actions { - heroscript:=install_action.heroscript() - mut obj2:=heroscript_loads(heroscript)! - set(obj2)! - } - } + mut install_actions := plbook.find(filter: 'mycelium.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + } + } - mut other_actions := plbook.find(filter: 'mycelium.')! - for other_action in other_actions { - if other_action.name in ["destroy","install","build"]{ - mut p := other_action.params - reset:=p.get_default_false("reset") - if other_action.name == "destroy" || reset{ - console.print_debug("install action mycelium.destroy") - destroy()! - } - if other_action.name == "install"{ - console.print_debug("install action mycelium.install") - install()! - } - } - if other_action.name in ["start","stop","restart"]{ - mut p := other_action.params - name := p.get('name')! - mut mycelium_obj:=get(name:name)! - console.print_debug("action object:\n${mycelium_obj}") - if other_action.name == "start"{ - console.print_debug("install action mycelium.${other_action.name}") - mycelium_obj.start()! - } - - if other_action.name == "stop"{ - console.print_debug("install action mycelium.${other_action.name}") - mycelium_obj.stop()! - } - if other_action.name == "restart"{ - console.print_debug("install action mycelium.${other_action.name}") - mycelium_obj.restart()! - } - } - } + mut other_actions := plbook.find(filter: 'mycelium.')! + for other_action in other_actions { + if other_action.name in ['destroy', 'install', 'build'] { + mut p := other_action.params + reset := p.get_default_false('reset') + if other_action.name == 'destroy' || reset { + console.print_debug('install action mycelium.destroy') + destroy()! + } + if other_action.name == 'install' { + console.print_debug('install action mycelium.install') + install()! + } + } + if other_action.name in ['start', 'stop', 'restart'] { + mut p := other_action.params + name := p.get('name')! + mut mycelium_obj := get(name: name)! + console.print_debug('action object:\n${mycelium_obj}') + if other_action.name == 'start' { + console.print_debug('install action mycelium.${other_action.name}') + mycelium_obj.start()! + } + if other_action.name == 'stop' { + console.print_debug('install action mycelium.${other_action.name}') + mycelium_obj.stop()! + } + if other_action.name == 'restart' { + console.print_debug('install action mycelium.${other_action.name}') + mycelium_obj.restart()! + } + } + } } - //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager { - // unknown - // screen - // zinit - // tmux - // systemd - match cat{ - .zinit{ - console.print_debug("startupmanager: zinit") - return startupmanager.get(cat:.zinit)! - } - .systemd{ - console.print_debug("startupmanager: systemd") - return startupmanager.get(cat:.systemd)! - }else{ - console.print_debug("startupmanager: auto") - return startupmanager.get()! - } - } + // unknown + // screen + // zinit + // tmux + // systemd + match cat { + .zinit { + console.print_debug('startupmanager: zinit') + return startupmanager.get(cat: .zinit)! + } + .systemd { + console.print_debug('startupmanager: systemd') + return startupmanager.get(cat: .systemd)! + } + else { + console.print_debug('startupmanager: auto') + return startupmanager.get()! + } + } } -//load from disk and make sure is properly intialized +// load from disk and make sure is properly intialized pub fn (mut self MyceliumInstaller) reload() ! { - switch(self.name) - self=obj_init(self)! + switch(self.name) + self = obj_init(self)! } pub fn (mut self MyceliumInstaller) start() ! { - switch(self.name) - if self.running()!{ - return - } + switch(self.name) + if self.running()! { + return + } - console.print_header('mycelium start') + console.print_header('mycelium start') - if ! installed()!{ - install()! - } + if !installed()! { + install()! + } - configure()! + configure()! - start_pre()! + start_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! - console.print_debug('starting mycelium with ${zprocess.startuptype}...') + console.print_debug('starting mycelium with ${zprocess.startuptype}...') - sm.new(zprocess)! + sm.new(zprocess)! - sm.start(zprocess.name)! - } + sm.start(zprocess.name)! + } - start_post()! - - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('mycelium did not install properly.') + start_post()! + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('mycelium did not install properly.') } pub fn (mut self MyceliumInstaller) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! + switch(self.name) + self.install(args)! + self.start()! } pub fn (mut self MyceliumInstaller) stop() ! { - switch(self.name) - stop_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - sm.stop(zprocess.name)! - } - stop_post()! + switch(self.name) + stop_pre()! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + sm.stop(zprocess.name)! + } + stop_post()! } pub fn (mut self MyceliumInstaller) restart() ! { - switch(self.name) - self.stop()! - self.start()! + switch(self.name) + self.stop()! + self.start()! } pub fn (mut self MyceliumInstaller) running() !bool { - switch(self.name) + switch(self.name) - //walk over the generic processes, if not running return - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - r:=sm.running(zprocess.name)! - if r==false{ - return false - } - } - return running()! + // walk over the generic processes, if not running return + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + r := sm.running(zprocess.name)! + if r == false { + return false + } + } + return running()! } @[params] -pub struct InstallArgs{ +pub struct InstallArgs { pub mut: - reset bool + reset bool } pub fn (mut self MyceliumInstaller) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } + switch(self.name) + if args.reset || (!installed()!) { + install()! + } } pub fn (mut self MyceliumInstaller) build() ! { - switch(self.name) - build()! + switch(self.name) + build()! } pub fn (mut self MyceliumInstaller) destroy() ! { - switch(self.name) - self.stop() or {} - destroy()! + switch(self.name) + self.stop() or {} + destroy()! } - - -//switch instance to be used for mycelium +// switch instance to be used for mycelium pub fn switch(name string) { - mycelium_default = name + mycelium_installer_default = name } - -//helpers +// helpers @[params] -pub struct DefaultConfigArgs{ - instance string = 'default' +pub struct DefaultConfigArgs { + instance string = 'default' } diff --git a/lib/installers/web/traefik/htpasswd.v b/lib/installers/web/traefik/htpasswd.v index 97d0df06..4302f730 100644 --- a/lib/installers/web/traefik/htpasswd.v +++ b/lib/installers/web/traefik/htpasswd.v @@ -5,8 +5,6 @@ import crypto.bcrypt // generate_htpasswd creates an Apache-style htpasswd entry for the given user and password // using bcrypt hashing with configurable cost (default 12) fn generate_htpasswd(user string, password string) !string { - - // Generate bcrypt hash hashed_password := bcrypt.generate_from_password(password.bytes(), 12) or { return error('Failed to hash password: ${err}') @@ -16,4 +14,4 @@ fn generate_htpasswd(user string, password string) !string { // Return final formatted string return '${user}:${hashed_password}' -} \ No newline at end of file +} diff --git a/lib/installers/web/traefik/traefik_actions.v b/lib/installers/web/traefik/traefik_actions.v index 147e0174..29c48f2c 100644 --- a/lib/installers/web/traefik/traefik_actions.v +++ b/lib/installers/web/traefik/traefik_actions.v @@ -3,125 +3,110 @@ module traefik import freeflowuniverse.herolib.osal import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.core.texttools - import freeflowuniverse.herolib.core import freeflowuniverse.herolib.osal.zinit import freeflowuniverse.herolib.installers.ulist - - import os -fn startupcmd () ![]zinit.ZProcessNewArgs{ - mut installer := get()! - mut res := []zinit.ZProcessNewArgs{} - res << zinit.ZProcessNewArgs{ - name: 'traefik' - cmd: 'traefik' - } +fn startupcmd() ![]zinit.ZProcessNewArgs { + mut installer := get()! + mut res := []zinit.ZProcessNewArgs{} + res << zinit.ZProcessNewArgs{ + name: 'traefik' + cmd: 'traefik' + } - return res - + return res } fn running() !bool { - cmd:="traefik healthcheck" - res := os.execute(cmd) - if res.exit_code != 0 { - return false - } - return true + cmd := 'traefik healthcheck' + res := os.execute(cmd) + if res.exit_code != 0 { + return false + } + return true } -fn start_pre()!{ - +fn start_pre() ! { } -fn start_post()!{ - +fn start_post() ! { } -fn stop_pre()!{ - +fn stop_pre() ! { } -fn stop_post()!{ - +fn stop_post() ! { } - //////////////////// following actions are not specific to instance of the object // checks if a certain version or above is installed fn installed() !bool { - res := os.execute('${osal.profile_path_source_and()!} traefik version') - if res.exit_code != 0 { - return false - } - r := res.output.split_into_lines().filter(it.contains("Version")) - if r.len != 1 { - return error("couldn't parse traefik version.\n${res.output}") - } - if texttools.version(version) == texttools.version(r[0].all_after("Version:")) { - return true - } - return false + res := os.execute('${osal.profile_path_source_and()!} traefik version') + if res.exit_code != 0 { + return false + } + r := res.output.split_into_lines().filter(it.contains('Version')) + if r.len != 1 { + return error("couldn't parse traefik version.\n${res.output}") + } + if texttools.version(version) == texttools.version(r[0].all_after('Version:')) { + return true + } + return false } -//get the Upload List of the files +// get the Upload List of the files fn ulist_get() !ulist.UList { - return ulist.UList{} + return ulist.UList{} } fn upload() ! { - // installers.upload( - // cmdname: 'traefik' - // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/traefik' - // )! - + // installers.upload( + // cmdname: 'traefik' + // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/traefik' + // )! } fn install() ! { - console.print_header('install traefik') - mut url := '' - if core.is_linux_arm()! { - url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_linux_arm64.tar.gz' - } else if core.is_linux_intel()! { - url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_linux_amd64.tar.gz' - } else if core.is_osx_arm()! { - url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_darwin_arm64.tar.gz' - } else if core.is_osx_intel()! { - url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_darwin_arm64.tar.gz' - } else { - return error('unsported platform') - } + console.print_header('install traefik') + mut url := '' + if core.is_linux_arm()! { + url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_linux_arm64.tar.gz' + } else if core.is_linux_intel()! { + url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_linux_amd64.tar.gz' + } else if core.is_osx_arm()! { + url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_darwin_arm64.tar.gz' + } else if core.is_osx_intel()! { + url = 'https://github.com/traefik/traefik/releases/download/v${version}/traefik_v${version}_darwin_arm64.tar.gz' + } else { + return error('unsported platform') + } - mut dest := osal.download( - url: url - minsize_kb: 20000 - expand_dir: '/tmp/traefik' - )! + mut dest := osal.download( + url: url + minsize_kb: 20000 + expand_dir: '/tmp/traefik' + )! - mut binpath := dest.file_get('traefik')! - osal.cmd_add( - cmdname: 'traefik' - source: binpath.path - )! + mut binpath := dest.file_get('traefik')! + osal.cmd_add( + cmdname: 'traefik' + source: binpath.path + )! } - fn destroy() ! { + osal.process_kill_recursive(name: 'traefik')! + osal.cmd_delete('traefik')! - osal.process_kill_recursive(name:'traefik')! - osal.cmd_delete('traefik')! - - osal.package_remove(' + osal.package_remove(' traefik ')! - osal.rm(" + osal.rm(' traefik - ")! - - + ')! } - diff --git a/lib/installers/web/traefik/traefik_factory_.v b/lib/installers/web/traefik/traefik_factory_.v index 520e6708..aa4cb3a3 100644 --- a/lib/installers/web/traefik/traefik_factory_.v +++ b/lib/installers/web/traefik/traefik_factory_.v @@ -4,284 +4,272 @@ import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.data.paramsparser - import freeflowuniverse.herolib.sysadmin.startupmanager import freeflowuniverse.herolib.osal.zinit import time __global ( - traefik_global map[string]&TraefikServer - traefik_default string + traefik_global map[string]&TraefikServer + traefik_default string ) /////////FACTORY @[params] -pub struct ArgsGet{ +pub struct ArgsGet { pub mut: - name string + name string } -fn args_get (args_ ArgsGet) ArgsGet { - mut args:=args_ - if args.name == ""{ - args.name = "default" - } - return args +fn args_get(args_ ArgsGet) ArgsGet { + mut args := args_ + if args.name == '' { + args.name = 'default' + } + return args } -pub fn get(args_ ArgsGet) !&TraefikServer { - mut context:=base.context()! - mut args := args_get(args_) - mut obj := TraefikServer{} - if !(args.name in traefik_global) { - if ! exists(args)!{ - set(obj)! - }else{ - heroscript := context.hero_config_get("traefik",args.name)! - mut obj_:=heroscript_loads(heroscript)! - set_in_mem(obj_)! - } - } - return traefik_global[args.name] or { - println(traefik_global) - //bug if we get here because should be in globals - panic("could not get config for traefik with name, is bug:${args.name}") - } +pub fn get(args_ ArgsGet) !&TraefikServer { + mut context := base.context()! + mut args := args_get(args_) + mut obj := TraefikServer{} + if args.name !in traefik_global { + if !exists(args)! { + set(obj)! + } else { + heroscript := context.hero_config_get('traefik', args.name)! + mut obj_ := heroscript_loads(heroscript)! + set_in_mem(obj_)! + } + } + return traefik_global[args.name] or { + println(traefik_global) + // bug if we get here because should be in globals + panic('could not get config for traefik with name, is bug:${args.name}') + } } -//register the config for the future -pub fn set(o TraefikServer)! { - set_in_mem(o)! - mut context := base.context()! - heroscript := heroscript_dumps(o)! - context.hero_config_set("traefik", o.name, heroscript)! +// register the config for the future +pub fn set(o TraefikServer) ! { + set_in_mem(o)! + mut context := base.context()! + heroscript := heroscript_dumps(o)! + context.hero_config_set('traefik', o.name, heroscript)! } -//does the config exists? -pub fn exists(args_ ArgsGet)! bool { - mut context := base.context()! - mut args := args_get(args_) - return context.hero_config_exists("traefik", args.name) +// does the config exists? +pub fn exists(args_ ArgsGet) !bool { + mut context := base.context()! + mut args := args_get(args_) + return context.hero_config_exists('traefik', args.name) } -pub fn delete(args_ ArgsGet)! { - mut args := args_get(args_) - mut context:=base.context()! - context.hero_config_delete("traefik",args.name)! - if args.name in traefik_global { - //del traefik_global[args.name] - } +pub fn delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context := base.context()! + context.hero_config_delete('traefik', args.name)! + if args.name in traefik_global { + // del traefik_global[args.name] + } } -//only sets in mem, does not set as config -fn set_in_mem(o TraefikServer)! { - mut o2:=obj_init(o)! - traefik_global[o.name] = &o2 - traefik_default = o.name +// only sets in mem, does not set as config +fn set_in_mem(o TraefikServer) ! { + mut o2 := obj_init(o)! + traefik_global[o.name] = &o2 + traefik_default = o.name } - @[params] pub struct PlayArgs { pub mut: - heroscript string //if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool + heroscript string // if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - - mut args:=args_ + mut args := args_ + mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } - mut plbook := args.plbook or { - playbook.new(text: args.heroscript)! - } - - mut install_actions := plbook.find(filter: 'traefik.configure')! - if install_actions.len > 0 { - for install_action in install_actions { - heroscript:=install_action.heroscript() - mut obj2:=heroscript_loads(heroscript)! - set(obj2)! - } - } + mut install_actions := plbook.find(filter: 'traefik.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + } + } - mut other_actions := plbook.find(filter: 'traefik.')! - for other_action in other_actions { - if other_action.name in ["destroy","install","build"]{ - mut p := other_action.params - reset:=p.get_default_false("reset") - if other_action.name == "destroy" || reset{ - console.print_debug("install action traefik.destroy") - destroy()! - } - if other_action.name == "install"{ - console.print_debug("install action traefik.install") - install()! - } - } - if other_action.name in ["start","stop","restart"]{ - mut p := other_action.params - name := p.get('name')! - mut traefik_obj:=get(name:name)! - console.print_debug("action object:\n${traefik_obj}") - if other_action.name == "start"{ - console.print_debug("install action traefik.${other_action.name}") - traefik_obj.start()! - } - - if other_action.name == "stop"{ - console.print_debug("install action traefik.${other_action.name}") - traefik_obj.stop()! - } - if other_action.name == "restart"{ - console.print_debug("install action traefik.${other_action.name}") - traefik_obj.restart()! - } - } - } + mut other_actions := plbook.find(filter: 'traefik.')! + for other_action in other_actions { + if other_action.name in ['destroy', 'install', 'build'] { + mut p := other_action.params + reset := p.get_default_false('reset') + if other_action.name == 'destroy' || reset { + console.print_debug('install action traefik.destroy') + destroy()! + } + if other_action.name == 'install' { + console.print_debug('install action traefik.install') + install()! + } + } + if other_action.name in ['start', 'stop', 'restart'] { + mut p := other_action.params + name := p.get('name')! + mut traefik_obj := get(name: name)! + console.print_debug('action object:\n${traefik_obj}') + if other_action.name == 'start' { + console.print_debug('install action traefik.${other_action.name}') + traefik_obj.start()! + } + if other_action.name == 'stop' { + console.print_debug('install action traefik.${other_action.name}') + traefik_obj.stop()! + } + if other_action.name == 'restart' { + console.print_debug('install action traefik.${other_action.name}') + traefik_obj.restart()! + } + } + } } - //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager { - // unknown - // screen - // zinit - // tmux - // systemd - match cat{ - .zinit{ - console.print_debug("startupmanager: zinit") - return startupmanager.get(cat:.zinit)! - } - .systemd{ - console.print_debug("startupmanager: systemd") - return startupmanager.get(cat:.systemd)! - }else{ - console.print_debug("startupmanager: auto") - return startupmanager.get()! - } - } + // unknown + // screen + // zinit + // tmux + // systemd + match cat { + .zinit { + console.print_debug('startupmanager: zinit') + return startupmanager.get(cat: .zinit)! + } + .systemd { + console.print_debug('startupmanager: systemd') + return startupmanager.get(cat: .systemd)! + } + else { + console.print_debug('startupmanager: auto') + return startupmanager.get()! + } + } } -//load from disk and make sure is properly intialized +// load from disk and make sure is properly intialized pub fn (mut self TraefikServer) reload() ! { - switch(self.name) - self=obj_init(self)! + switch(self.name) + self = obj_init(self)! } pub fn (mut self TraefikServer) start() ! { - switch(self.name) - if self.running()!{ - return - } + switch(self.name) + if self.running()! { + return + } - console.print_header('traefik start') + console.print_header('traefik start') - if ! installed()!{ - install()! - } + if !installed()! { + install()! + } - configure()! + configure()! - start_pre()! + start_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! - console.print_debug('starting traefik with ${zprocess.startuptype}...') + console.print_debug('starting traefik with ${zprocess.startuptype}...') - sm.new(zprocess)! + sm.new(zprocess)! - sm.start(zprocess.name)! - } + sm.start(zprocess.name)! + } - start_post()! - - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('traefik did not install properly.') + start_post()! + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('traefik did not install properly.') } pub fn (mut self TraefikServer) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! + switch(self.name) + self.install(args)! + self.start()! } pub fn (mut self TraefikServer) stop() ! { - switch(self.name) - stop_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - sm.stop(zprocess.name)! - } - stop_post()! + switch(self.name) + stop_pre()! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + sm.stop(zprocess.name)! + } + stop_post()! } pub fn (mut self TraefikServer) restart() ! { - switch(self.name) - self.stop()! - self.start()! + switch(self.name) + self.stop()! + self.start()! } pub fn (mut self TraefikServer) running() !bool { - switch(self.name) + switch(self.name) - //walk over the generic processes, if not running return - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - r:=sm.running(zprocess.name)! - if r==false{ - return false - } - } - return running()! + // walk over the generic processes, if not running return + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + r := sm.running(zprocess.name)! + if r == false { + return false + } + } + return running()! } @[params] -pub struct InstallArgs{ +pub struct InstallArgs { pub mut: - reset bool + reset bool } pub fn (mut self TraefikServer) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } + switch(self.name) + if args.reset || (!installed()!) { + install()! + } } - pub fn (mut self TraefikServer) destroy() ! { - switch(self.name) - self.stop() or {} - destroy()! + switch(self.name) + self.stop() or {} + destroy()! } - - -//switch instance to be used for traefik +// switch instance to be used for traefik pub fn switch(name string) { - traefik_default = name + traefik_default = name } - -//helpers +// helpers @[params] -pub struct DefaultConfigArgs{ - instance string = 'default' +pub struct DefaultConfigArgs { + instance string = 'default' } diff --git a/lib/installers/web/traefik/traefik_model.v b/lib/installers/web/traefik/traefik_model.v index 8ab1e2a6..50c12db9 100644 --- a/lib/installers/web/traefik/traefik_model.v +++ b/lib/installers/web/traefik/traefik_model.v @@ -1,4 +1,5 @@ module traefik + import freeflowuniverse.herolib.data.paramsparser import freeflowuniverse.herolib.data.encoderhero import os @@ -9,46 +10,43 @@ pub const version = '3.3.3' const singleton = true const default = true -//THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED +// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED @[heap] pub struct TraefikServer { pub mut: - name string = 'default' - // homedir string - // configpath string - // username string - password string @[secret] - // title string - // host string - // port int + name string = 'default' + // homedir string + // configpath string + // username string + password string @[secret] + // title string + // host string + // port int } - - -//your checking & initialization code if needed -fn obj_init(mycfg_ TraefikServer)!TraefikServer{ - mut mycfg:=mycfg_ - return mycfg +// your checking & initialization code if needed +fn obj_init(mycfg_ TraefikServer) !TraefikServer { + mut mycfg := mycfg_ + return mycfg } -//called before start if done +// called before start if done fn configure() ! { - mut installer := get()! - htaccesscode:=generate_htpasswd("admin",installer.password)! - mut mycode := $tmpl('templates/traefik.toml') - mut path := pathlib.get_file(path: "/etc/traefik/traefik.toml", create: true)! - path.write(mycode)! - console.print_debug(mycode) + mut installer := get()! + htaccesscode := generate_htpasswd('admin', installer.password)! + mut mycode := $tmpl('templates/traefik.toml') + mut path := pathlib.get_file(path: '/etc/traefik/traefik.toml', create: true)! + path.write(mycode)! + console.print_debug(mycode) } - /////////////NORMALLY NO NEED TO TOUCH pub fn heroscript_dumps(obj TraefikServer) !string { - return encoderhero.encode[TraefikServer ](obj)! + return encoderhero.encode[TraefikServer](obj)! } pub fn heroscript_loads(heroscript string) !TraefikServer { - mut obj := encoderhero.decode[TraefikServer](heroscript)! - return obj + mut obj := encoderhero.decode[TraefikServer](heroscript)! + return obj } diff --git a/lib/osal/coredns/README.md b/lib/osal/coredns/README.md new file mode 100644 index 00000000..951db5c7 --- /dev/null +++ b/lib/osal/coredns/README.md @@ -0,0 +1,95 @@ +# CoreDNS Redis Record Management + +This module provides functionality for managing DNS records in Redis for use with CoreDNS. It supports various DNS record types and provides a simple interface for adding and managing DNS records. + +```v +import freeflowuniverse.herolib.lib.osal.coredns + +// Create a new DNS record set +mut rs := coredns.new_dns_record_set() + +// Create and populate DNS records +rs.set_soa(mbox: 'hostmaster.example.net.', ns: 'ns1.example.net.') +rs.add_srv(target: 'tcp.example.com.', port: 123) +rs.add_txt(text: 'this is a wildcard') +rs.add_mx(host: 'host1.example.net.') +rs.add_a(name: 'host1', ip: '5.5.5.5') +rs.add_aaaa(name: 'host1', ip: '2001:db8::1') +rs.add_ns(host: 'ns1.example.net.') +rs.add_ns(host: 'ns2.example.net.') + +// Store records in Redis +rs.set('example.com')! +``` + + +## Record Types + +The following DNS record types are supported: + +### SRV Record +```v +SRVRecord { + target string // Required: Target hostname + port int // Required: Port number + priority int // Default: 10 + weight int // Default: 100 + ttl int // Default: 300 +} +``` + +### TXT Record +```v +TXTRecord { + text string // Required: Text content + ttl int // Default: 300 +} +``` + +### MX Record +```v +MXRecord { + host string // Required: Mail server hostname + preference int // Default: 10 + ttl int // Default: 300 +} +``` + +### A Record +```v +ARecord { + name string // Required: Hostname + ip string // Required: IPv4 address + ttl int // Default: 300 +} +``` + +### AAAA Record +```v +AAAARecord { + name string // Required: Hostname + ip string // Required: IPv6 address + ttl int // Default: 300 +} +``` + +### NS Record +```v +NSRecord { + host string // Required: Nameserver hostname + ttl int // Default: 300 +} +``` + +### SOA Record +```v +SOARecord { + mbox string // Required: Email address of the admin + ns string // Required: Primary nameserver + refresh int // Default: 44 + retry int // Default: 55 + expire int // Default: 66 + minttl int // Default: 100 + ttl int // Default: 300 +} +``` diff --git a/lib/osal/coredns/model.v b/lib/osal/coredns/model.v new file mode 100644 index 00000000..7432cf1d --- /dev/null +++ b/lib/osal/coredns/model.v @@ -0,0 +1,73 @@ +// Input parameter structs for each record type +@[params] +struct SRVRecord { +pub mut: + target string @[required] + port int @[required] + priority int = 10 + weight int = 100 + ttl int = 300 +} + +@[params] +struct TXTRecord { +pub mut: + text string @[required] + ttl int = 300 +} + +@[params] +struct MXRecord { +pub mut: + host string @[required] + preference int = 10 + ttl int = 300 +} + +@[params] +struct ARecord { +pub mut: + name string @[required] + ip string @[required] + ttl int = 300 +} + +@[params] +struct AAAARecord { +pub mut: + name string @[required] + ip string @[required] + ttl int = 300 +} + +@[params] +struct NSRecord { +pub mut: + host string @[required] + ttl int = 300 +} + +@[params] +struct SOARecord { +pub mut: + mbox string @[required] + ns string @[required] + refresh int = 44 + retry int = 55 + expire int = 66 + minttl int = 100 + ttl int = 300 +} + +// DNSRecordSet represents a set of DNS records +struct DNSRecordSet { +pub mut: + srv []SRVRecord + txt []TXTRecord + mx []MXRecord + a []ARecord + aaaa []AAAARecord + ns []NSRecord + soa ?SOARecord + redis ?&redisclient.Redis +} diff --git a/lib/osal/coredns/play.v b/lib/osal/coredns/play.v new file mode 100644 index 00000000..e27b48fc --- /dev/null +++ b/lib/osal/coredns/play.v @@ -0,0 +1,119 @@ +module coredns + +import freeflowuniverse.herolib.core.playbook + +// play_dns processes DNS-related actions from heroscript +pub fn play_dns(mut plbook playbook.PlayBook) !DNSRecordSet { + mut recordset := new_dns_record_set() + + // Find all actions starting with dns. + dns_actions := plbook.find(filter: 'dns.')! + + for action in dns_actions { + mut p := action.params + + match action.name { + 'a_record' { + recordset.add_a( + name: p.get('name')! + ip: p.get('ip')! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'aaaa_record' { + recordset.add_aaaa( + name: p.get('name')! + ip: p.get('ip')! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'mx_record' { + recordset.add_mx( + host: p.get('host')! + preference: p.get_int_default('preference', 10)! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'txt_record' { + recordset.add_txt( + text: p.get('text')! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'srv_record' { + recordset.add_srv( + target: p.get('target')! + port: p.get_int('port')! + priority: p.get_int_default('priority', 10)! + weight: p.get_int_default('weight', 100)! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'ns_record' { + recordset.add_ns( + host: p.get('host')! + ttl: p.get_int_default('ttl', 300)! + ) + } + 'soa_record' { + recordset.set_soa( + mbox: p.get('mbox')! + ns: p.get('ns')! + refresh: p.get_int_default('refresh', 44)! + retry: p.get_int_default('retry', 55)! + expire: p.get_int_default('expire', 66)! + minttl: p.get_int_default('minttl', 100)! + ttl: p.get_int_default('ttl', 300)! + ) + } + else { + // Unknown action, skip + continue + } + } + } + + return recordset +} + +// Example usage: +/* +!!dns.a_record + name: 'host1' + ip: '1.2.3.4' + ttl: 300 + +!!dns.aaaa_record + name: 'host1' + ip: '2001:db8::1' + ttl: 300 + +!!dns.mx_record + host: 'mail.example.com' + preference: 10 + ttl: 300 + +!!dns.txt_record + text: 'v=spf1 mx ~all' + ttl: 300 + +!!dns.srv_record + target: 'sip.example.com' + port: 5060 + priority: 10 + weight: 100 + ttl: 300 + +!!dns.ns_record + host: 'ns1.example.com' + ttl: 300 + +!!dns.soa_record + mbox: 'hostmaster.example.com' + ns: 'ns1.example.com' + refresh: 44 + retry: 55 + expire: 66 + minttl: 100 + ttl: 300 +*/ diff --git a/lib/osal/coredns/populator.v b/lib/osal/coredns/populator.v new file mode 100644 index 00000000..7bdb743b --- /dev/null +++ b/lib/osal/coredns/populator.v @@ -0,0 +1,279 @@ +module coredns + +import json +import freeflowuniverse.herolib.core.redisclient + +// Input parameter structs for each record type +@[params] +struct SRVRecord { +pub mut: + target string @[required] + port int @[required] + priority int = 10 + weight int = 100 + ttl int = 300 +} + +@[params] +struct TXTRecord { +pub mut: + text string @[required] + ttl int = 300 +} + +@[params] +struct MXRecord { +pub mut: + host string @[required] + preference int = 10 + ttl int = 300 +} + +@[params] +struct ARecord { +pub mut: + name string @[required] + ip string @[required] + ttl int = 300 +} + +@[params] +struct AAAARecord { +pub mut: + name string @[required] + ip string @[required] + ttl int = 300 +} + +@[params] +struct NSRecord { +pub mut: + host string @[required] + ttl int = 300 +} + +@[params] +struct SOARecord { +pub mut: + mbox string @[required] + ns string @[required] + refresh int = 44 + retry int = 55 + expire int = 66 + minttl int = 100 + ttl int = 300 +} + +// DNSRecordSet represents a set of DNS records +struct DNSRecordSet { +pub mut: + srv []SRVRecord + txt []TXTRecord + mx []MXRecord + a []ARecord + aaaa []AAAARecord + ns []NSRecord + soa ?SOARecord + redis ?&redisclient.Redis +} + +// new_dns_record_set creates a new DNSRecordSet +pub fn new_dns_record_set() DNSRecordSet { + return DNSRecordSet{ + srv: []SRVRecord{} + txt: []TXTRecord{} + mx: []MXRecord{} + a: []ARecord{} + aaaa: []AAAARecord{} + ns: []NSRecord{} + } +} + +// add_srv adds an SRV record to the set +pub fn (mut rs DNSRecordSet) add_srv(args SRVRecord) { + rs.srv << SRVRecord{ + target: args.target + port: args.port + priority: args.priority + weight: args.weight + ttl: args.ttl + } +} + +// add_txt adds a TXT record to the set +pub fn (mut rs DNSRecordSet) add_txt(args TXTRecord) { + rs.txt << TXTRecord{ + text: args.text + ttl: args.ttl + } +} + +// add_mx adds an MX record to the set +pub fn (mut rs DNSRecordSet) add_mx(args MXRecord) { + rs.mx << MXRecord{ + host: args.host + preference: args.preference + ttl: args.ttl + } +} + +// add_a adds an A record to the set +pub fn (mut rs DNSRecordSet) add_a(args ARecord) { + rs.a << ARecord{ + name: args.name + ip: args.ip + ttl: args.ttl + } +} + +// add_aaaa adds an AAAA record to the set +pub fn (mut rs DNSRecordSet) add_aaaa(args AAAARecord) { + rs.aaaa << AAAARecord{ + name: args.name + ip: args.ip + ttl: args.ttl + } +} + +// add_ns adds an NS record to the set +pub fn (mut rs DNSRecordSet) add_ns(args NSRecord) { + rs.ns << NSRecord{ + host: args.host + ttl: args.ttl + } +} + +// set_soa sets the SOA record for the set +pub fn (mut rs DNSRecordSet) set_soa(args SOARecord) { + rs.soa = SOARecord{ + mbox: args.mbox + ns: args.ns + refresh: args.refresh + retry: args.retry + expire: args.expire + minttl: args.minttl + ttl: args.ttl + } +} + +// populate_redis populates Redis with the DNS records +// domain e.g. example.com. (not sure the . is at end) +pub fn (rs DNSRecordSet) set(domain string) ! { + mut redis := rs.redis or { redisclient.core_get()! } + + // Store SRV records + for srv in rs.srv { + key := '_ssh._tcp.host1' + value := json.encode({ + 'srv': { + 'ttl': srv.ttl + 'target': srv.target + 'port': srv.port + 'priority': srv.priority + 'weight': srv.weight + } + }) + redis.hset(domain, key, value)! + } + + // Store TXT and MX records for wildcard + if rs.txt.len > 0 || rs.mx.len > 0 { + mut records := map[string]map[string]json.Any{} + if rs.txt.len > 0 { + records['txt'] = { + 'text': rs.txt[0].text + 'ttl': '${rs.txt[0].ttl}' + } + } + if rs.mx.len > 0 { + records['mx'] = { + 'host': rs.mx[0].host + 'priority': rs.mx[0].preference + 'ttl': rs.mx[0].ttl + } + } + redis.hset(domain, '*', json.encode(records))! + } + + // Store A records + for a in rs.a { + value := json.encode({ + 'a': { + 'ip4': a.ip + 'ttl': '${a.ttl}' + } + }) + redis.hset(domain, a.name, value)! + } + + // Store AAAA records + for aaaa in rs.aaaa { + value := json.encode({ + 'aaaa': { + 'ip6': aaaa.ip + 'ttl': aaaa.ttl + } + }) + redis.hset(domain, aaaa.name, value)! + } + + // Store NS records + if rs.ns.len > 0 { + mut ns_records := []map[string]json.Any{} + for ns in rs.ns { + ns_records << { + 'host': ns.host + 'ttl': ns.ttl + } + } + value := json.encode({ + 'ns': ns_records + }) + redis.hset(domain, 'subdel', value)! + } + + // Store SOA and root NS records at @ + if soa := rs.soa { + mut root_records := map[string]json.Any{} + root_records['soa'] = { + 'ttl': soa.ttl + 'minttl': soa.minttl + 'mbox': soa.mbox + 'ns': soa.ns + 'refresh': soa.refresh + 'retry': soa.retry + 'expire': soa.expire + } + + if rs.ns.len > 0 { + mut ns_records := []map[string]json.Any{} + for ns in rs.ns { + ns_records << { + 'host': ns.host + 'ttl': ns.ttl + } + } + root_records['ns'] = ns_records + } + + redis.hset(domain, '@', json.encode(root_records))! + } +} + +pub fn (mut rs DNSRecordSet) example() ! { + // Create and populate DNS records + rs.set_soa(mbox: 'hostmaster.example.net.', ns: 'ns1.example.net.') + rs.add_srv(target: 'tcp.example.com.', port: 123) + rs.add_txt(text: 'this is a wildcard') + rs.add_mx(host: 'host1.example.net.') + rs.add_a(name: 'host1', ip: '5.5.5.5') + rs.add_aaaa(name: 'host1', ip: '2001:db8::1') + rs.add_txt(text: 'this is not a wildcard') + rs.add_ns(host: 'ns1.subdel.example.net.') + rs.add_ns(host: 'ns2.subdel.example.net.') + rs.add_ns(host: 'ns1.example.net.') + rs.add_ns(host: 'ns2.example.net.') + + // Store records in Redis + rs.set('example.com')! +} diff --git a/lib/osal/net.v b/lib/osal/net.v index f2b3559c..2414271a 100644 --- a/lib/osal/net.v +++ b/lib/osal/net.v @@ -104,36 +104,40 @@ pub fn tcp_port_test(args TcpPortTestArgs) bool { // Returns the public IP address as known on the public side // Uses resolver4.opendns.com to fetch the IP address pub fn ipaddr_pub_get() !string { - cmd := 'dig @resolver4.opendns.com myip.opendns.com +short' - ipaddr := exec(cmd: cmd)! - public_ip := ipaddr.output.trim('\n').trim(' \n') - - // Check if the public IP matches any local interface - if ! is_ip_on_local_interface(public_ip)! { - return error ('Public IP $public_ip is NOT bound to any local interface (possibly behind a NAT firewall).') - } + cmd := 'dig @resolver4.opendns.com myip.opendns.com +short' + ipaddr := exec(cmd: cmd)! + public_ip := ipaddr.output.trim('\n').trim(' \n') + return public_ip +} - return public_ip +//also check the address is on local interface +pub fn ipaddr_pub_get_check() !string { + // Check if the public IP matches any local interface + public_ip := ipaddr_pub_get_check()! + if !is_ip_on_local_interface(public_ip)! { + return error('Public IP ${public_ip} is NOT bound to any local interface (possibly behind a NAT firewall).') + } + return public_ip } // Check if the public IP matches any of the local network interfaces pub fn is_ip_on_local_interface(public_ip string) !bool { - interfaces := exec(cmd:'ip addr show',stdout:false) or { - return error ('Failed to enumerate network interfaces.') - } - lines := interfaces.output.split('\n') + interfaces := exec(cmd: 'ip addr show', stdout: false) or { + return error('Failed to enumerate network interfaces.') + } + lines := interfaces.output.split('\n') - // Parse through the `ip addr show` output to find local IPs - for line in lines { - if line.contains('inet ') { - parts := line.trim_space().split(' ') - if parts.len > 1 { - local_ip := parts[1].split('/')[0] // Extract the IP address - if public_ip == local_ip { - return true - } - } - } - } - return false + // Parse through the `ip addr show` output to find local IPs + for line in lines { + if line.contains('inet ') { + parts := line.trim_space().split(' ') + if parts.len > 1 { + local_ip := parts[1].split('/')[0] // Extract the IP address + if public_ip == local_ip { + return true + } + } + } + } + return false }