From 3e309b63794dcc1564eed1a644783d779838fa7a Mon Sep 17 00:00:00 2001 From: despiegk Date: Sun, 9 Feb 2025 12:24:12 +0100 Subject: [PATCH] ... --- examples/clients/mycelium.vsh | 36 +- examples/installers/coredns.vsh | 6 +- examples/installers/traefik.vsh | 13 + lib/clients/mycelium/mycelium.v | 93 +++-- lib/clients/mycelium/mycelium_factory_.v | 2 - lib/clients/mycelium/mycelium_model.v | 1 - .../templates/objname_actions.vtemplate | 9 +- lib/installers/infra/coredns/.heroscript | 13 + lib/installers/infra/coredns/cdns_install.v | 138 ------- lib/installers/infra/coredns/cdns_play.v | 49 --- .../infra/coredns/coredns_actions.v | 183 +++++++++ .../{cdns_configure.v => coredns_configure.v} | 24 +- .../infra/coredns/coredns_factory_.v | 291 ++++++++++++++ lib/installers/infra/coredns/coredns_fix.v | 62 +++ lib/installers/infra/coredns/coredns_model.v | 42 ++ lib/installers/infra/coredns/readme.md | 43 ++ .../infra/coredns/templates/Corefile | 4 +- .../infra/coredns/templates/db.example.org | 14 - .../infra/coredns/templates/ourexample.org | 17 + .../net/mycelium/mycelium_actions.v | 261 ++++++------ .../net/mycelium/mycelium_actions_0.v | 167 ++++++++ .../net/mycelium/mycelium_factory_.v | 375 +++++++++--------- lib/installers/net/mycelium/mycelium_model.v | 74 ++-- .../net/mycelium/mycelium_model_0.v | 74 ++++ lib/installers/web/traefik/.heroscript | 11 + lib/installers/web/traefik/htpasswd.v | 19 + lib/installers/web/traefik/readme.md | 21 + .../web/traefik/templates/traefik.toml | 36 ++ lib/installers/web/traefik/traefik_actions.v | 127 ++++++ lib/installers/web/traefik/traefik_factory_.v | 287 ++++++++++++++ lib/installers/web/traefik/traefik_model.v | 54 +++ lib/osal/net.v | 40 +- 32 files changed, 1968 insertions(+), 618 deletions(-) create mode 100755 examples/installers/traefik.vsh create mode 100644 lib/installers/infra/coredns/.heroscript delete mode 100644 lib/installers/infra/coredns/cdns_install.v delete mode 100644 lib/installers/infra/coredns/cdns_play.v create mode 100644 lib/installers/infra/coredns/coredns_actions.v rename lib/installers/infra/coredns/{cdns_configure.v => coredns_configure.v} (73%) create mode 100644 lib/installers/infra/coredns/coredns_factory_.v create mode 100644 lib/installers/infra/coredns/coredns_fix.v create mode 100644 lib/installers/infra/coredns/coredns_model.v create mode 100644 lib/installers/infra/coredns/readme.md delete mode 100644 lib/installers/infra/coredns/templates/db.example.org create mode 100644 lib/installers/infra/coredns/templates/ourexample.org create mode 100644 lib/installers/net/mycelium/mycelium_actions_0.v create mode 100644 lib/installers/net/mycelium/mycelium_model_0.v create mode 100644 lib/installers/web/traefik/.heroscript create mode 100644 lib/installers/web/traefik/htpasswd.v create mode 100644 lib/installers/web/traefik/readme.md create mode 100644 lib/installers/web/traefik/templates/traefik.toml create mode 100644 lib/installers/web/traefik/traefik_actions.v create mode 100644 lib/installers/web/traefik/traefik_factory_.v create mode 100644 lib/installers/web/traefik/traefik_model.v diff --git a/examples/clients/mycelium.vsh b/examples/clients/mycelium.vsh index 9b598c1c..ce748573 100755 --- a/examples/clients/mycelium.vsh +++ b/examples/clients/mycelium.vsh @@ -12,31 +12,31 @@ println(client) // Send a message to a node by public key // Parameters: public_key, payload, topic, wait_for_reply -msg := client.send_msg(r.public_key, // destination public key - 'Hello World', // message payload - 'greetings', // optional topic - false // 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(true, false, 'greetings')! +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( -// received.id, // original message ID -// received.src_pk, // sender's public key -// 'Got your message!', // reply payload -// 'greetings' // topic -// )! +// 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}') +// 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 dda45b90..aa4bd9fe 100755 --- a/examples/installers/coredns.vsh +++ b/examples/installers/coredns.vsh @@ -1,5 +1,9 @@ #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer +import freeflowuniverse.herolib.osal + +// coredns_installer.delete()! +mut installer:= coredns_installer.get()! +installer.build()! -coredns_installer.install()! diff --git a/examples/installers/traefik.vsh b/examples/installers/traefik.vsh new file mode 100755 index 00000000..47af5179 --- /dev/null +++ b/examples/installers/traefik.vsh @@ -0,0 +1,13 @@ +#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run +import os + +import freeflowuniverse.herolib.installers.web.traefik as traefik_installer + + +traefik_installer.delete()! +mut installer:= traefik_installer.get()! + +installer.password = "planet" +traefik_installer.set(installer)! + +installer.start()! diff --git a/lib/clients/mycelium/mycelium.v b/lib/clients/mycelium/mycelium.v index 9e7a9613..4c68f2c2 100644 --- a/lib/clients/mycelium/mycelium.v +++ b/lib/clients/mycelium/mycelium.v @@ -15,8 +15,8 @@ pub: pub struct PushMessageBody { pub: dst MessageDestination - topic string // optional message topic - payload string // base64 encoded message + topic ?string // optional message topic + payload string // base64 encoded message } // Response containing message ID after pushing @@ -73,19 +73,32 @@ pub fn (mut self Mycelium) connection() !&httpconnection.HTTPConnection { return c } +@[params] +pub struct SendMessageArgs { +pub mut: + public_key string @[required] + payload string @[required] + topic ?string + wait bool +} + // Send a message to a node identified by public key -pub fn (mut self Mycelium) send_msg(pk string, payload string, topic string, wait bool) !InboundMessage { +pub fn (mut self Mycelium) send_msg(args SendMessageArgs) !InboundMessage { mut conn := self.connection()! mut body := PushMessageBody{ dst: MessageDestination{ - pk: pk + pk: args.public_key ip: '' } - payload: base64.encode_str(payload) - topic: base64.encode_str(topic) + payload: base64.encode_str(args.payload) + topic: if v := args.topic { + base64.encode_str(v) + } else { + none + } } mut prefix := '/api/v1/messages' - if wait { + if args.wait { prefix += '?reply_timeout=120' } return conn.post_json_generic[InboundMessage]( @@ -96,19 +109,27 @@ pub fn (mut self Mycelium) send_msg(pk string, payload string, topic string, wai )! } +@[params] +pub struct ReceiveMessageArgs { +pub mut: + topic ?string + wait bool + peek bool +} + // Receive a message from the queue -pub fn (mut self Mycelium) receive_msg(wait bool, peek bool, topic string) !InboundMessage { +pub fn (mut self Mycelium) receive_msg(args ReceiveMessageArgs) !InboundMessage { mut conn := self.connection()! - mut prefix := '/api/v1/messages?' - if wait { - prefix += 'timeout=60&' + mut prefix := '/api/v1/messages?peek=${args.peek}&' + + if args.wait { + prefix += 'timeout=120&' } - if peek { - prefix += 'peek=true&' - } - if topic.len > 0 { - prefix += 'topic=${base64.encode_str(topic)}' + + if v := args.topic { + prefix += 'topic=${base64.encode_str(v)}' } + return conn.get_json_generic[InboundMessage]( method: .get prefix: prefix @@ -117,23 +138,8 @@ pub fn (mut self Mycelium) receive_msg(wait bool, peek bool, topic string) !Inbo } // Optional version of receive_msg that returns none on 204 -pub fn (mut self Mycelium) receive_msg_opt(wait bool, peek bool, topic string) ?InboundMessage { - mut conn := self.connection() or { panic(err) } - mut prefix := '/api/v1/messages?' - if wait { - prefix += 'timeout=60&' - } - if peek { - prefix += 'peek=true&' - } - if topic.len > 0 { - prefix += 'topic=${base64.encode_str(topic)}' - } - res := conn.get_json_generic[InboundMessage]( - method: .get - prefix: prefix - dataformat: .json - ) or { +pub fn (mut self Mycelium) receive_msg_opt(args ReceiveMessageArgs) ?InboundMessage { + res := self.receive_msg(args) or { if err.msg().contains('204') { return none } @@ -152,20 +158,29 @@ pub fn (mut self Mycelium) get_msg_status(id string) !MessageStatusResponse { )! } +@[params] +pub struct ReplyMessageArgs { +pub mut: + id string @[required] + public_key string @[required] + payload string @[required] + topic ?string +} + // Reply to a message -pub fn (mut self Mycelium) reply_msg(id string, pk string, payload string, topic string) ! { +pub fn (mut self Mycelium) reply_msg(args ReplyMessageArgs) ! { mut conn := self.connection()! mut body := PushMessageBody{ dst: MessageDestination{ - pk: pk + pk: args.public_key ip: '' } - payload: base64.encode_str(payload) - topic: base64.encode_str(topic) + payload: base64.encode_str(args.payload) + topic: if v := args.topic { base64.encode_str(v) } else { none } } - _ := conn.post_json_generic[MessageDestination]( + _ := conn.post_json_str( method: .post - prefix: '/api/v1/messages/reply/${id}' + prefix: '/api/v1/messages/reply/${args.id}' data: json.encode(body) dataformat: .json )! diff --git a/lib/clients/mycelium/mycelium_factory_.v b/lib/clients/mycelium/mycelium_factory_.v index ac0729e5..0c2c4736 100644 --- a/lib/clients/mycelium/mycelium_factory_.v +++ b/lib/clients/mycelium/mycelium_factory_.v @@ -2,8 +2,6 @@ module mycelium import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook -import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.data.paramsparser __global ( mycelium_global map[string]&Mycelium diff --git a/lib/clients/mycelium/mycelium_model.v b/lib/clients/mycelium/mycelium_model.v index 911faa40..bc3eb791 100644 --- a/lib/clients/mycelium/mycelium_model.v +++ b/lib/clients/mycelium/mycelium_model.v @@ -2,7 +2,6 @@ module mycelium import freeflowuniverse.herolib.core.httpconnection import freeflowuniverse.herolib.data.encoderhero -import os pub const version = '0.0.0' const singleton = true diff --git a/lib/code/generator/installer_client/templates/objname_actions.vtemplate b/lib/code/generator/installer_client/templates/objname_actions.vtemplate index 619e6967..fe98d634 100644 --- a/lib/code/generator/installer_client/templates/objname_actions.vtemplate +++ b/lib/code/generator/installer_client/templates/objname_actions.vtemplate @@ -152,11 +152,16 @@ fn build_() ! { // if core.platform()!= .ubuntu { // return error('only support ubuntu for now') // } - // golang.install()! + + //mut g:=golang.get()! + //g.install()! + //console.print_header('build coredns') + + //mut gs := gittools.new(coderoot: '~/code')! // console.print_header('build ${model.name}') - // gitpath := gittools.get_repo(coderoot: '/tmp/builder', url: url, reset: true, pull: true)! + // gitpath := gittools.get_repo(url: url, reset: true, pull: true)! // cmd := ' // cd ??{gitpath} diff --git a/lib/installers/infra/coredns/.heroscript b/lib/installers/infra/coredns/.heroscript new file mode 100644 index 00000000..7bb6ac10 --- /dev/null +++ b/lib/installers/infra/coredns/.heroscript @@ -0,0 +1,13 @@ + +!!hero_code.generate_installer + name:'coredns' + classname:'CoreDNS' + singleton:1 + templates:1 + default:1 + title:'coredns' + supported_platforms:'' + reset:0 + startupmanager:1 + hasconfig:1 + build:1 \ No newline at end of file diff --git a/lib/installers/infra/coredns/cdns_install.v b/lib/installers/infra/coredns/cdns_install.v deleted file mode 100644 index ded49d5a..00000000 --- a/lib/installers/infra/coredns/cdns_install.v +++ /dev/null @@ -1,138 +0,0 @@ -module coredns - -import freeflowuniverse.herolib.osal -import freeflowuniverse.herolib.osal.screen -import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.core.texttools -import freeflowuniverse.herolib.core.httpconnection -import os - -@[params] -pub struct InstallArgs { -pub mut: - reset bool // this means we re-install and forgot what we did before - start bool = true - stop bool - restart bool // this means we stop if started, otherwise just start - homedir string // not sure what this is? - config_path string // path to Corefile, if empty will install default one - 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 - plugins []string // list of plugins to build CoreDNS with - example bool // if true we will install examples -} - -pub fn install_(args_ InstallArgs) ! { - mut args := args_ - version := '1.11.1' - - res := os.execute('${osal.profile_path_source_and()!} coredns version') - if res.exit_code == 0 { - 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-')) { - args.reset = true - } - } else { - args.reset = true - } - - if args.reset { - 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') - } - - 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 - )! - } - - configure(args)! - - if args.example { - example_configure(args)! - } - - if args.restart { - restart(args)! - return - } - - if args.start { - start(args)! - } -} - -pub fn restart(args_ InstallArgs) ! { - stop(args_)! - start(args_)! -} - -pub fn stop(args_ InstallArgs) ! { - console.print_header('coredns stop') - - name := 'coredns' - - // use startup manager, see caddy - mut scr := screen.new()! - scr.kill(name)! -} - -pub fn start(args_ InstallArgs) ! { - mut args := args_ - configure(args)! - - if check()! { - return - } - - console.print_header('coredns start') - - name := 'coredns' - - mut scr := screen.new()! - - mut s := scr.add(name: name, reset: true)! - - cmd2 := "coredns -conf '${args.config_path}'" - - s.cmd_send(cmd2)! - - if !check()! { - return error("coredns did not install propertly, do: curl 'http://localhost:3334/health'") - } - - console.print_header('coredns running') -} - -pub fn check() !bool { - // this checks health of coredns - mut conn := httpconnection.new(name: 'coredns', url: 'http://localhost:3334')! - r := conn.get(prefix: 'health')! - if r.trim_space() == 'OK' { - return true - } - return false -} diff --git a/lib/installers/infra/coredns/cdns_play.v b/lib/installers/infra/coredns/cdns_play.v deleted file mode 100644 index 867ef632..00000000 --- a/lib/installers/infra/coredns/cdns_play.v +++ /dev/null @@ -1,49 +0,0 @@ -module coredns - -import freeflowuniverse.herolib.core.playbook -import freeflowuniverse.herolib.installers.base -import os - -pub fn play(mut plbook playbook.PlayBook) ! { - base.play(playbook)! - - coredns_actions := plbook.find(filter: 'coredns.')! - if coredns_actions.len == 0 { - return - } - - mut install_actions := plbook.find(filter: 'coredns.install')! - - if install_actions.len > 0 { - for install_action in install_actions { - mut p := install_action.params - - // CoreDNS parameters - reset := p.get_default_false('reset') - start := p.get_default_true('start') - stop := p.get_default_false('stop') - restart := p.get_default_false('restart') - homedir := p.get_default('homedir', '${os.home_dir()}/hero/var/coredns')! - config_path := p.get_default('config_path', '${os.home_dir()}/hero/cfg/Corefile')! - config_url := p.get_default('config_url', '')! - dnszones_path := p.get_default('dnszones_path', '${os.home_dir()}/hero/var/coredns/zones')! - dnszones_url := p.get_default('dnszones_url', '')! - plugins := p.get_list_default('plugins', [])! - example := p.get_default_false('example') - - install( - reset: reset - start: start - stop: stop - restart: restart - homedir: homedir - config_path: config_path - config_url: config_url - dnszones_path: dnszones_path - dnszones_url: dnszones_url - plugins: plugins - example: example - )! - } - } -} diff --git a/lib/installers/infra/coredns/coredns_actions.v b/lib/installers/infra/coredns/coredns_actions.v new file mode 100644 index 00000000..5b987a7e --- /dev/null +++ b/lib/installers/infra/coredns/coredns_actions.v @@ -0,0 +1,183 @@ +module coredns + +import freeflowuniverse.herolib.osal +import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.core.texttools +import freeflowuniverse.herolib.core.pathlib +import freeflowuniverse.herolib.core +import freeflowuniverse.herolib.develop.gittools +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 running() !bool { + 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_post()!{ + set_local_dns() +} + +fn stop_pre()!{ + +} + +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 +} + +//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{} +} + +//uploads to S3 server if configured +fn upload() ! { + // 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') + } + + 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 + )! +} + +fn build() ! { + url := 'https://github.com/coredns/coredns' + + if core.platform()! != .ubuntu { + return error('only support ubuntu for now') + } + mut g:=golang.get()! + g.install()! + + console.print_header('build coredns') + + mut gs := gittools.new(coderoot: '~/code')! + + gitpath := gs.get_repo(url: url, reset: true, pull: true)! + + 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 + // )! + +} + +fn destroy() ! { + + // mut systemdfactory := systemd.new()! + // systemdfactory.destroy("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 + // ")! + + +} + diff --git a/lib/installers/infra/coredns/cdns_configure.v b/lib/installers/infra/coredns/coredns_configure.v similarity index 73% rename from lib/installers/infra/coredns/cdns_configure.v rename to lib/installers/infra/coredns/coredns_configure.v index 57cadce6..5aa053e2 100644 --- a/lib/installers/infra/coredns/cdns_configure.v +++ b/lib/installers/infra/coredns/coredns_configure.v @@ -1,14 +1,18 @@ module coredns import freeflowuniverse.herolib.core.pathlib +import freeflowuniverse.herolib.osal import freeflowuniverse.herolib.develop.gittools import os -pub fn configure(args_ InstallArgs) ! { - mut args := args_ +pub fn configure() ! { + mut args := get()! mut gs := gittools.get()! mut repo_path := '' + set_global_dns() + + if args.config_url.len > 0 { mut repo := gs.get_repo( url: args.config_url @@ -37,15 +41,23 @@ pub fn configure(args_ InstallArgs) ! { mycorefile := $tmpl('templates/Corefile') mut path := pathlib.get_file(path: args.config_path, create: true)! path.write(mycorefile)! + + if args.example{ + example_configure() ! + } + } -pub fn example_configure(args_ InstallArgs) ! { - mut args := args_ +pub fn example_configure() ! { + mut args := get()! - exampledbfile := $tmpl('templates/db.example.org') + myipaddr:=osal.ipaddr_pub_get()! + + + exampledbfile := $tmpl('templates/ourexample.org') mut path_testzone := pathlib.get_file( - path: '${args_.dnszones_path}/db.example.org' + path: '${args.dnszones_path}/ourexample.org' create: true )! path_testzone.template_write(exampledbfile, true)! diff --git a/lib/installers/infra/coredns/coredns_factory_.v b/lib/installers/infra/coredns/coredns_factory_.v new file mode 100644 index 00000000..d39772bf --- /dev/null +++ b/lib/installers/infra/coredns/coredns_factory_.v @@ -0,0 +1,291 @@ +module coredns + +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 +) + +/////////FACTORY + +@[params] +pub struct ArgsGet{ +pub mut: + name string +} + +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}") + } +} + +//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) +} + +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 +} + + +@[params] +pub struct PlayArgs { +pub mut: + 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 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 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()! + } + } +} + +//load from disk and make sure is properly intialized +pub fn (mut self CoreDNS) reload() ! { + switch(self.name) + self=obj_init(self)! +} + +pub fn (mut self CoreDNS) start() ! { + switch(self.name) + if self.running()!{ + return + } + + console.print_header('coredns start') + + if ! installed()!{ + install()! + } + + configure()! + + start_pre()! + + for zprocess in startupcmd()!{ + mut sm:=startupmanager_get(zprocess.startuptype)! + + console.print_debug('starting coredns with ${zprocess.startuptype}...') + + sm.new(zprocess)! + + 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.') + +} + +pub fn (mut self CoreDNS) install_start(args InstallArgs) ! { + 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()! +} + +pub fn (mut self CoreDNS) restart() ! { + switch(self.name) + self.stop()! + self.start()! +} + +pub fn (mut self CoreDNS) running() !bool { + 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()! +} + +@[params] +pub struct InstallArgs{ +pub mut: + reset bool +} + +pub fn (mut self CoreDNS) install(args InstallArgs) ! { + switch(self.name) + if args.reset || (!installed()!) { + install()! + } +} + +pub fn (mut self CoreDNS) build() ! { + switch(self.name) + build()! +} + +pub fn (mut self CoreDNS) destroy() ! { + switch(self.name) + self.stop() or {} + destroy()! +} + + + +//switch instance to be used for coredns +pub fn switch(name string) { + coredns_default = name +} + + +//helpers + +@[params] +pub struct DefaultConfigArgs{ + instance string = 'default' +} diff --git a/lib/installers/infra/coredns/coredns_fix.v b/lib/installers/infra/coredns/coredns_fix.v new file mode 100644 index 00000000..3544ec50 --- /dev/null +++ b/lib/installers/infra/coredns/coredns_fix.v @@ -0,0 +1,62 @@ +module coredns + +import os +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' +} + +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') +} + +fn is_dns_port_free() bool { + 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.') +} + +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.') +} + +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 + } + + 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 new file mode 100644 index 00000000..d0147287 --- /dev/null +++ b/lib/installers/infra/coredns/coredns_model.v @@ -0,0 +1,42 @@ +module coredns +import freeflowuniverse.herolib.data.paramsparser +import freeflowuniverse.herolib.data.encoderhero +import os + +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 +@[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) + plugins string // list of plugins to build CoreDNS with (is comma or \n separated list) + 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 +} + + + +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj CoreDNS) !string { + return encoderhero.encode[CoreDNS ](obj)! +} + +pub fn heroscript_loads(heroscript string) !CoreDNS { + mut obj := encoderhero.decode[CoreDNS](heroscript)! + return obj +} diff --git a/lib/installers/infra/coredns/readme.md b/lib/installers/infra/coredns/readme.md new file mode 100644 index 00000000..2cee25f9 --- /dev/null +++ b/lib/installers/infra/coredns/readme.md @@ -0,0 +1,43 @@ +# coredns + +coredns + +To get started + +```vlang + + +import freeflowuniverse.herolib.lib.installers.infra.coredns as coredns_installer + +heroscript:=" +!!coredns.configure name:'test' + config_path: '/etc/coredns/Corefile' + dnszones_path: '/etc/coredns/zones' + plugins: 'forward,cache' + example: true + +!!coredns.start name:'test' reset:1 +" + +coredns_installer.play(heroscript=heroscript)! + +//or we can call the default and do a start with reset +//mut installer:= coredns_installer.get()! +//installer.start(reset:true)! + + + +``` + +## example heroscript + +```hero +!!coredns.configure + name: 'custom' + config_path: '/etc/coredns/Corefile' + config_url: 'https://github.com/example/coredns-config' + dnszones_path: '/etc/coredns/zones' + dnszones_url: 'https://github.com/example/dns-zones' + plugins: 'forward,cache' + example: false +``` \ No newline at end of file diff --git a/lib/installers/infra/coredns/templates/Corefile b/lib/installers/infra/coredns/templates/Corefile index 110c192b..b9740d8f 100644 --- a/lib/installers/infra/coredns/templates/Corefile +++ b/lib/installers/infra/coredns/templates/Corefile @@ -3,5 +3,7 @@ log errors health :3334 - import '${args.dnszones_path}/*' + auto ${args.dnszones_path} { + reload 30s + } } diff --git a/lib/installers/infra/coredns/templates/db.example.org b/lib/installers/infra/coredns/templates/db.example.org deleted file mode 100644 index e316525e..00000000 --- a/lib/installers/infra/coredns/templates/db.example.org +++ /dev/null @@ -1,14 +0,0 @@ -??ORIGIN example.org. -^^ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. ( - 2017042745 ; serial - 7200 ; refresh (2 hours) - 3600 ; retry (1 hour) - 1209600 ; expire (2 weeks) - 3600 ; minimum (1 hour) - ) - - 3600 IN NS a.iana-servers.net. - 3600 IN NS b.iana-servers.net. - -www IN A 127.0.0.1 - IN AAAA ::1 \ No newline at end of file diff --git a/lib/installers/infra/coredns/templates/ourexample.org b/lib/installers/infra/coredns/templates/ourexample.org new file mode 100644 index 00000000..4032b7e7 --- /dev/null +++ b/lib/installers/infra/coredns/templates/ourexample.org @@ -0,0 +1,17 @@ +??ORIGIN ourexample.org. +^^ 3600 IN SOA ns1.ourexample.org. hostmaster.ourexample.org. ( + 2017042745 ; serial + 7200 ; refresh (2 hours) + 3600 ; retry (1 hour) + 1209600 ; expire (2 weeks) + 3600 ; minimum (1 hour) + ) + + 3600 IN NS ns1.ourexample.org. + 3600 IN NS ns2.ourexample.org. + +ns1 IN A ${myipaddr} +ns2 IN A ${myipaddr} +www IN A ${myipaddr} +test IN A ${myipaddr} + IN AAAA ::1 \ No newline at end of file diff --git a/lib/installers/net/mycelium/mycelium_actions.v b/lib/installers/net/mycelium/mycelium_actions.v index d08383bc..24a6921b 100644 --- a/lib/installers/net/mycelium/mycelium_actions.v +++ b/lib/installers/net/mycelium/mycelium_actions.v @@ -3,165 +3,200 @@ module mycelium import freeflowuniverse.herolib.osal import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.core.texttools -import freeflowuniverse.herolib.core import freeflowuniverse.herolib.core.pathlib -import freeflowuniverse.herolib.installers.sysadmintools.zinit as zinit_installer -import freeflowuniverse.herolib.clients.mycelium -import freeflowuniverse.herolib.develop.gittools + +import freeflowuniverse.herolib.osal.systemd import freeflowuniverse.herolib.osal.zinit import freeflowuniverse.herolib.installers.ulist + +import freeflowuniverse.herolib.installers.lang.golang import freeflowuniverse.herolib.installers.lang.rust +import freeflowuniverse.herolib.installers.lang.python + import os -fn startupcmd() ![]zinit.ZProcessNewArgs { - mut installer := get()! - mut res := []zinit.ZProcessNewArgs{} +fn startupcmd () ![]zinit.ZProcessNewArgs{ + mut installer := get()! + mut res := []zinit.ZProcessNewArgs{} + //THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // res << zinit.ZProcessNewArgs{ + // name: 'mycelium' + // cmd: 'mycelium server' + // env: { + // 'HOME': '/root' + // } + // } - mut peers_str := installer.peers.join(' ') - mut tun_name := 'tun${installer.tun_nr}' - - res << zinit.ZProcessNewArgs{ - name: 'mycelium' - cmd: 'mycelium --key-file ${osal.hero_path()!}/cfg/priv_key.bin --peers ${peers_str} --tun-name ${tun_name}' - env: { - 'HOME': '/root' - } - } - - return res + return res + } fn running() !bool { - mycelium.inspect() or { return false } - return true + mut installer := get()! + //THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // this checks health of mycelium + // curl http://localhost:3333/api/v1/s --oauth2-bearer 1234 works + // url:='http://127.0.0.1:${cfg.port}/api/v1' + // mut conn := httpconnection.new(name: 'mycelium', url: url)! + + // if cfg.secret.len > 0 { + // conn.default_header.add(.authorization, 'Bearer ${cfg.secret}') + // } + // conn.default_header.add(.content_type, 'application/json') + // console.print_debug("curl -X 'GET' '${url}'/tags --oauth2-bearer ${cfg.secret}") + // r := conn.get_json_dict(prefix: 'tags', debug: false) or {return false} + // println(r) + // if true{panic("ssss")} + // tags := r['Tags'] or { return false } + // console.print_debug(tags) + // console.print_debug('mycelium is answering.') + return false } -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 { - cmd := '${osal.profile_path_source_and()!} mycelium -V' - // println(cmd) - res := os.execute(cmd) - if res.exit_code != 0 { - println(res) - return false - } - r := res.output.split_into_lines().filter(it.trim_space().len > 0) - if r.len != 1 { - return error("couldn't parse mycelium version.\n${res.output}") - } - if texttools.version(version) == texttools.version(r[0].all_after_last('mycelium')) { - return true - } - return false + //THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // res := os.execute('${osal.profile_path_source_and()!} mycelium version') + // if res.exit_code != 0 { + // return false + // } + // r := res.output.split_into_lines().filter(it.trim_space().len > 0) + // if r.len != 1 { + // return error("couldn't parse mycelium version.\n${res.output}") + // } + // if texttools.version(version) == texttools.version(r[0]) { + // 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: 'mycelium' - // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/mycelium' - // )! + // installers.upload( + // cmdname: 'mycelium' + // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/mycelium' + // )! + } fn install() ! { - console.print_header('install mycelium') + console.print_header('install mycelium') + //THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // mut url := '' + // if core.is_linux_arm() { + // url = 'https://github.com/mycelium-dev/mycelium/releases/download/v${version}/mycelium_${version}_linux_arm64.tar.gz' + // } else if core.is_linux_intel() { + // url = 'https://github.com/mycelium-dev/mycelium/releases/download/v${version}/mycelium_${version}_linux_amd64.tar.gz' + // } else if core.is_osx_arm() { + // url = 'https://github.com/mycelium-dev/mycelium/releases/download/v${version}/mycelium_${version}_darwin_arm64.tar.gz' + // } else if osal.is_osx_intel() { + // url = 'https://github.com/mycelium-dev/mycelium/releases/download/v${version}/mycelium_${version}_darwin_amd64.tar.gz' + // } else { + // return error('unsported platform') + // } - mut z_installer := zinit_installer.get()! - z_installer.start()! + // mut dest := osal.download( + // url: url + // minsize_kb: 9000 + // expand_dir: '/tmp/mycelium' + // )! - mut url := '' - if core.is_linux_arm()! { - url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-aarch64-unknown-linux-musl.tar.gz' - } else if core.is_linux_intel()! { - url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-x86_64-unknown-linux-musl.tar.gz' - } else if core.is_osx_arm()! { - url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-aarch64-apple-darwin.tar.gz' - } else if core.is_osx_intel()! { - url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-x86_64-apple-darwin.tar.gz' - } else { - return error('unsported platform') - } + // //dest.moveup_single_subdir()! - pathlib.get_dir( - path: '${osal.hero_path()!}/cfg' - create: true - )! - - mut dest := osal.download( - url: url - minsize_kb: 5000 - expand_dir: '/tmp/mycelium' - )! - mut binpath := dest.file_get('mycelium')! - osal.cmd_add( - cmdname: 'mycelium' - source: binpath.path - )! + // mut binpath := dest.file_get('mycelium')! + // osal.cmd_add( + // cmdname: 'mycelium' + // source: binpath.path + // )! } fn build() ! { - url := 'https://github.com/threefoldtech/mycelium' - myplatform := core.platform()! - if myplatform != .ubuntu { - return error('only support ubuntu for now') - } - rust.install()! + //url := 'https://github.com/threefoldtech/mycelium' - console.print_header('build mycelium') + // make sure we install base on the node + // if osal.platform() != .ubuntu { + // return error('only support ubuntu for now') + // } + // golang.install()! - mut gs := gittools.new()! - gitpath := gs.get_path( - pull: true - reset: false - url: url - )! + // console.print_header('build mycelium') - panic('implement') + // gitpath := gittools.get_repo(coderoot: '/tmp/builder', url: url, reset: true, pull: true)! - cmd := ' - cd ${gitpath} - source ~/.cargo/env - cargo install --path . --locked - cargo build --release --locked --no-default-features --features=native-tls - cp target/release/mycelium ~/.cargo/bin/mycelium - mycelium --version - ' - osal.execute_stdout(cmd)! + // cmd := ' + // cd ${gitpath} + // source ~/.cargo/env + // exit 1 #todo + // ' + // 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 + // )! - // //now copy to the default bin path - // mut binpath := dest.file_get('...')! - // adds it to path - // osal.cmd_add( - // cmdname: 'griddriver2' - // source: binpath.path - // )! } fn destroy() ! { - osal.process_kill_recursive(name: 'mycelium')! - osal.cmd_delete('mycelium')! - osal.rm(' - mycelium - ')! + // mut systemdfactory := systemd.new()! + // systemdfactory.destroy("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 + // ")! + + } + diff --git a/lib/installers/net/mycelium/mycelium_actions_0.v b/lib/installers/net/mycelium/mycelium_actions_0.v new file mode 100644 index 00000000..d08383bc --- /dev/null +++ b/lib/installers/net/mycelium/mycelium_actions_0.v @@ -0,0 +1,167 @@ +module mycelium + +import freeflowuniverse.herolib.osal +import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.core.texttools +import freeflowuniverse.herolib.core +import freeflowuniverse.herolib.core.pathlib +import freeflowuniverse.herolib.installers.sysadmintools.zinit as zinit_installer +import freeflowuniverse.herolib.clients.mycelium +import freeflowuniverse.herolib.develop.gittools +import freeflowuniverse.herolib.osal.zinit +import freeflowuniverse.herolib.installers.ulist +import freeflowuniverse.herolib.installers.lang.rust +import os + +fn startupcmd() ![]zinit.ZProcessNewArgs { + mut installer := get()! + mut res := []zinit.ZProcessNewArgs{} + + mut peers_str := installer.peers.join(' ') + mut tun_name := 'tun${installer.tun_nr}' + + res << zinit.ZProcessNewArgs{ + name: 'mycelium' + cmd: 'mycelium --key-file ${osal.hero_path()!}/cfg/priv_key.bin --peers ${peers_str} --tun-name ${tun_name}' + env: { + 'HOME': '/root' + } + } + + return res +} + +fn running() !bool { + mycelium.inspect() or { return false } + return true +} + +fn start_pre() ! { +} + +fn start_post() ! { +} + +fn stop_pre() ! { +} + +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 { + cmd := '${osal.profile_path_source_and()!} mycelium -V' + // println(cmd) + res := os.execute(cmd) + if res.exit_code != 0 { + println(res) + return false + } + r := res.output.split_into_lines().filter(it.trim_space().len > 0) + if r.len != 1 { + return error("couldn't parse mycelium version.\n${res.output}") + } + if texttools.version(version) == texttools.version(r[0].all_after_last('mycelium')) { + return true + } + return false +} + +// 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{} +} + +// uploads to S3 server if configured +fn upload() ! { + // installers.upload( + // cmdname: 'mycelium' + // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/mycelium' + // )! +} + +fn install() ! { + console.print_header('install mycelium') + + mut z_installer := zinit_installer.get()! + z_installer.start()! + + mut url := '' + if core.is_linux_arm()! { + url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-aarch64-unknown-linux-musl.tar.gz' + } else if core.is_linux_intel()! { + url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-x86_64-unknown-linux-musl.tar.gz' + } else if core.is_osx_arm()! { + url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-aarch64-apple-darwin.tar.gz' + } else if core.is_osx_intel()! { + url = 'https://github.com/threefoldtech/mycelium/releases/download/v${version}/mycelium-x86_64-apple-darwin.tar.gz' + } else { + return error('unsported platform') + } + + pathlib.get_dir( + path: '${osal.hero_path()!}/cfg' + create: true + )! + + mut dest := osal.download( + url: url + minsize_kb: 5000 + expand_dir: '/tmp/mycelium' + )! + mut binpath := dest.file_get('mycelium')! + osal.cmd_add( + cmdname: 'mycelium' + source: binpath.path + )! +} + +fn build() ! { + url := 'https://github.com/threefoldtech/mycelium' + myplatform := core.platform()! + if myplatform != .ubuntu { + return error('only support ubuntu for now') + } + rust.install()! + + console.print_header('build mycelium') + + mut gs := gittools.new()! + gitpath := gs.get_path( + pull: true + reset: false + url: url + )! + + panic('implement') + + cmd := ' + cd ${gitpath} + source ~/.cargo/env + cargo install --path . --locked + cargo build --release --locked --no-default-features --features=native-tls + cp target/release/mycelium ~/.cargo/bin/mycelium + mycelium --version + ' + 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 + // )! +} + +fn destroy() ! { + osal.process_kill_recursive(name: 'mycelium')! + osal.cmd_delete('mycelium')! + + osal.rm(' + mycelium + ')! +} diff --git a/lib/installers/net/mycelium/mycelium_factory_.v b/lib/installers/net/mycelium/mycelium_factory_.v index 1527b72e..fefa2188 100644 --- a/lib/installers/net/mycelium/mycelium_factory_.v +++ b/lib/installers/net/mycelium/mycelium_factory_.v @@ -4,277 +4,288 @@ 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_global map[string]&MyceliumInstaller + mycelium_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_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}") + } } -// 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_global { + //del mycelium_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_global[o.name] = &o2 + mycelium_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 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 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 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()! - } + 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()! + } + } + } - 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()! + start_post()! + + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('mycelium did not install properly.') - 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_default = name } -// helpers + +//helpers @[params] -pub struct DefaultConfigArgs { - instance string = 'default' +pub struct DefaultConfigArgs{ + instance string = 'default' } diff --git a/lib/installers/net/mycelium/mycelium_model.v b/lib/installers/net/mycelium/mycelium_model.v index 6619177e..c0962e81 100644 --- a/lib/installers/net/mycelium/mycelium_model.v +++ b/lib/installers/net/mycelium/mycelium_model.v @@ -1,70 +1,50 @@ module mycelium - +import freeflowuniverse.herolib.data.paramsparser import freeflowuniverse.herolib.data.encoderhero -import freeflowuniverse.herolib.osal.tun import os -pub const version = '0.5.7' -const singleton = true +pub const version = '0.0.0' +const singleton = false 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 MyceliumInstaller { pub mut: - name string = 'default' - peers []string = [ - '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_nr 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_ MyceliumInstaller) !MyceliumInstaller { - mut mycfg := mycfg_ - return mycfg + + +//your checking & initialization code if needed +fn obj_init(mycfg_ MyceliumInstaller)!MyceliumInstaller{ + mut mycfg:=mycfg_ + if mycfg.password == '' && mycfg.secret == '' { + return error('password or secret needs to be filled in for ${mycfg.name}') + } + return mycfg } -// called before start if done +//called before start if done fn configure() ! { - mut installer := get()! - if installer.tun_nr == 0 { - // Check if TUN is available first - if available := tun.available() { - if !available { - return error('TUN is not available on this system') - } - // Get free TUN interface name - if interface_name := tun.free() { - // Parse the interface number from the name (e.g. "tun0" -> 0) - nr := interface_name.trim_string_left('tun').int() - installer.tun_nr = nr - } else { - return error('Failed to get free TUN interface: ${err}') - } - } else { - return error('Failed to check TUN availability: ${err}') - } - set(installer)! - } + //mut installer := get()! } + /////////////NORMALLY NO NEED TO TOUCH pub fn heroscript_dumps(obj MyceliumInstaller) !string { - return encoderhero.encode[MyceliumInstaller](obj)! + return encoderhero.encode[MyceliumInstaller ](obj)! } pub fn heroscript_loads(heroscript string) !MyceliumInstaller { - mut obj := encoderhero.decode[MyceliumInstaller](heroscript)! - return obj + mut obj := encoderhero.decode[MyceliumInstaller](heroscript)! + return obj } diff --git a/lib/installers/net/mycelium/mycelium_model_0.v b/lib/installers/net/mycelium/mycelium_model_0.v new file mode 100644 index 00000000..ee55cfba --- /dev/null +++ b/lib/installers/net/mycelium/mycelium_model_0.v @@ -0,0 +1,74 @@ +module mycelium + +import freeflowuniverse.herolib.data.encoderhero +import freeflowuniverse.herolib.osal.tun + +pub const version = '0.5.7' +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 +@[heap] +pub struct MyceliumInstaller { +pub mut: + name string = 'default' + peers []string = [ + '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_nr int = 1 + tcp_listen_port int = 9651 + quic_listen_port int = 9651 + peer_discovery_port int = 9650 + api_address string = '127.0.0.1:8989' + key_file string = 'priv_key.bin' +} + +// your checking & initialization code if needed +fn obj_init(mycfg_ MyceliumInstaller) !MyceliumInstaller { + mut mycfg := mycfg_ + return mycfg +} + +// called before start if done +fn configure() ! { + mut installer := get()! + if installer.tun_nr == 0 { + // Check if TUN is available first + if available := tun.available() { + if !available { + return error('TUN is not available on this system') + } + // Get free TUN interface name + if interface_name := tun.free() { + // Parse the interface number from the name (e.g. "tun0" -> 0) + nr := interface_name.trim_string_left('tun').int() + installer.tun_nr = nr + } else { + return error('Failed to get free TUN interface: ${err}') + } + } else { + return error('Failed to check TUN availability: ${err}') + } + set(installer)! + } +} + +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj MyceliumInstaller) !string { + return encoderhero.encode[MyceliumInstaller](obj)! +} + +pub fn heroscript_loads(heroscript string) !MyceliumInstaller { + mut obj := encoderhero.decode[MyceliumInstaller](heroscript)! + return obj +} diff --git a/lib/installers/web/traefik/.heroscript b/lib/installers/web/traefik/.heroscript new file mode 100644 index 00000000..a6718889 --- /dev/null +++ b/lib/installers/web/traefik/.heroscript @@ -0,0 +1,11 @@ + +!!hero_code.generate_installer + name:'traefik' + classname:'TraefikServer' + singleton:1 //there can only be 1 object in the globals, is called 'default' + templates:1 //are there templates for the installer + default:1 //can we create a default when the factory is used + title:'' + supported_platforms:'' //osx, ... (empty means all) + reset:0 // regenerate all, dangerous !!! + startupmanager:1 //managed by a startup manager, default true \ No newline at end of file diff --git a/lib/installers/web/traefik/htpasswd.v b/lib/installers/web/traefik/htpasswd.v new file mode 100644 index 00000000..97d0df06 --- /dev/null +++ b/lib/installers/web/traefik/htpasswd.v @@ -0,0 +1,19 @@ +module traefik + +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}') + } + + println(hashed_password) + + // Return final formatted string + return '${user}:${hashed_password}' +} \ No newline at end of file diff --git a/lib/installers/web/traefik/readme.md b/lib/installers/web/traefik/readme.md new file mode 100644 index 00000000..1409995f --- /dev/null +++ b/lib/installers/web/traefik/readme.md @@ -0,0 +1,21 @@ +# traefik + + + +To get started + +```vlang + + + +import freeflowuniverse.herolib.installers.web.traefik as traefik_installer + +mut installer:= traefik_installer.get()! + +installer.start()! + + + + +``` + diff --git a/lib/installers/web/traefik/templates/traefik.toml b/lib/installers/web/traefik/templates/traefik.toml new file mode 100644 index 00000000..fdfda62e --- /dev/null +++ b/lib/installers/web/traefik/templates/traefik.toml @@ -0,0 +1,36 @@ +[api] + dashboard = true + debug = false + +[entryPoints] + [entryPoints.http] + address = ":80" + + [entryPoints.https] + address = ":443" + +# [providers] +# [providers.file] +# filename = "/etc/traefik/dynamic_conf.toml" +# watch = true + +[log] + level = "WARN" + +[accessLog] + +[middlewares] + [middlewares.basicAuth] + [middlewares.basicAuth.basicAuth] + users = [ + "${htaccesscode}" + ] + realm = "Traefik Dashboard" + removeHeader = true + +[http.routers] + [http.routers.api] + rule = "Host(`traefik.local`)" + service = "api^^internal" + entryPoints = ["https"] + middlewares = ["basicAuth"] diff --git a/lib/installers/web/traefik/traefik_actions.v b/lib/installers/web/traefik/traefik_actions.v new file mode 100644 index 00000000..147e0174 --- /dev/null +++ b/lib/installers/web/traefik/traefik_actions.v @@ -0,0 +1,127 @@ +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' + } + + return res + +} + +fn running() !bool { + cmd:="traefik healthcheck" + res := os.execute(cmd) + if res.exit_code != 0 { + return false + } + return true +} + +fn start_pre()!{ + +} + +fn start_post()!{ + +} + +fn stop_pre()!{ + +} + +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 +} + +//get the Upload List of the files +fn ulist_get() !ulist.UList { + return ulist.UList{} +} + +fn upload() ! { + // 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') + } + + 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 + )! +} + + +fn destroy() ! { + + osal.process_kill_recursive(name:'traefik')! + osal.cmd_delete('traefik')! + + osal.package_remove(' + traefik + ')! + + osal.rm(" + traefik + ")! + + +} + diff --git a/lib/installers/web/traefik/traefik_factory_.v b/lib/installers/web/traefik/traefik_factory_.v new file mode 100644 index 00000000..520e6708 --- /dev/null +++ b/lib/installers/web/traefik/traefik_factory_.v @@ -0,0 +1,287 @@ +module traefik + +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 +) + +/////////FACTORY + +@[params] +pub struct ArgsGet{ +pub mut: + name string +} + +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}") + } +} + +//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) +} + +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 +} + + +@[params] +pub struct PlayArgs { +pub mut: + 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 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 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()! + } + } +} + +//load from disk and make sure is properly intialized +pub fn (mut self TraefikServer) reload() ! { + switch(self.name) + self=obj_init(self)! +} + +pub fn (mut self TraefikServer) start() ! { + switch(self.name) + if self.running()!{ + return + } + + console.print_header('traefik start') + + if ! installed()!{ + install()! + } + + configure()! + + start_pre()! + + for zprocess in startupcmd()!{ + mut sm:=startupmanager_get(zprocess.startuptype)! + + console.print_debug('starting traefik with ${zprocess.startuptype}...') + + sm.new(zprocess)! + + 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.') + +} + +pub fn (mut self TraefikServer) install_start(args InstallArgs) ! { + 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()! +} + +pub fn (mut self TraefikServer) restart() ! { + switch(self.name) + self.stop()! + self.start()! +} + +pub fn (mut self TraefikServer) running() !bool { + 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()! +} + +@[params] +pub struct InstallArgs{ +pub mut: + reset bool +} + +pub fn (mut self TraefikServer) install(args InstallArgs) ! { + switch(self.name) + if args.reset || (!installed()!) { + install()! + } +} + + +pub fn (mut self TraefikServer) destroy() ! { + switch(self.name) + self.stop() or {} + destroy()! +} + + + +//switch instance to be used for traefik +pub fn switch(name string) { + traefik_default = name +} + + +//helpers + +@[params] +pub struct DefaultConfigArgs{ + instance string = 'default' +} diff --git a/lib/installers/web/traefik/traefik_model.v b/lib/installers/web/traefik/traefik_model.v new file mode 100644 index 00000000..8ab1e2a6 --- /dev/null +++ b/lib/installers/web/traefik/traefik_model.v @@ -0,0 +1,54 @@ +module traefik +import freeflowuniverse.herolib.data.paramsparser +import freeflowuniverse.herolib.data.encoderhero +import os +import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.core.pathlib + +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 +@[heap] +pub struct TraefikServer { +pub mut: + 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 +} + +//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) +} + + +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj TraefikServer) !string { + return encoderhero.encode[TraefikServer ](obj)! +} + +pub fn heroscript_loads(heroscript string) !TraefikServer { + mut obj := encoderhero.decode[TraefikServer](heroscript)! + return obj +} diff --git a/lib/osal/net.v b/lib/osal/net.v index 14b1ebf6..f2b3559c 100644 --- a/lib/osal/net.v +++ b/lib/osal/net.v @@ -4,6 +4,7 @@ import net import time import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.core +import os pub enum PingResult { ok @@ -100,10 +101,39 @@ pub fn tcp_port_test(args TcpPortTestArgs) bool { return false } -// Returns the ipaddress as known on the public side -// is using resolver4.opendns.com +// 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)! - return ipaddr.output.trim('\n').trim(' \n') + 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).') + } + + 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') + + // 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 }