Mercurial Hosting > luan
changeset 1995:301a6561fb6b
add host/admin
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 04 Jul 2025 10:25:38 -0600 |
parents | 035996323891 |
children | d5c21ca9703e |
files | .hgignore host/admin/push-local.sh host/admin/push.sh host/admin/read_me.txt host/admin/serve.sh host/admin/src/hi.luan host/admin/src/init.luan host/admin/src/private/Config_sample.luan host/admin/src/private/host/Config.luan host/admin/src/private/lib/Utils.luan host/admin/src/private/lib/monitor.luan host/admin/src/private/tools/admin.html.luan host/admin/src/private/tools/clean_logs.luan host/admin/src/private/tools/java_threads.html.luan host/admin/src/private/tools/links.html host/admin/src/private/tools/luan_threads.html.luan host/admin/src/private/tools/request.txt.luan host/admin/src/private/tools/run.luan host/admin/src/private/tools/shell.html.luan host/admin/src/private/tools/sites.html.luan |
diffstat | 20 files changed, 485 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Jul 03 22:23:58 2025 -0600 +++ b/.hgignore Fri Jul 04 10:25:38 2025 -0600 @@ -18,3 +18,4 @@ backup/backups.copy/ mine/ private/Config.luan +changeset.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/push-local.sh Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +hg identify >src/private/changeset.txt + +PASSWORD="$(luan 'string:require("luan:Io.luan").stdout.write(require("file:src/private/Config.luan").push_password)')" + +luan luan:host/push.luan admin.me.luan.software "$PASSWORD" src 2>&1 | tee err
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/push.sh Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +hg identify >src/private/changeset.txt + +PASSWORD="$(luan 'string:require("luan:Io.luan").stdout.write(require("file:src/private/Config.luan").push_password)')" + +luan luan:host/push.luan admin.s1.luan.software "$PASSWORD" src 2>&1 | tee err +luan luan:host/push.luan admin.s2.luan.software "$PASSWORD" src 2>&1 | tee err
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/read_me.txt Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,4 @@ +To configure, go to src/private and copy Config_sample.luan to Config.luan . Then update Config.luan as needed. + +If you have access, you can get Config.luan here: +https://hg.reactionary.software/repo/config/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/serve.sh Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,3 @@ +#!/bin/bash + +luan luan:http/serve.luan src 2>&1 | tee err
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/hi.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,8 @@ +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" + + +return function() + Io.stdout = Http.response.text_writer() + %>hi<% +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/init.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,10 @@ +local Http = require "luan:http/Http.luan" +local Hosted = require "luan:host/Hosted.luan" + +Hosted.set_https and Hosted.set_https(true) + +require "site:/private/lib/monitor.luan" + +Http.dont_gc and Http.dont_gc() + +return true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/Config_sample.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,6 @@ +return { + email_to = "x@x.com" + mail_password = "xxx" + hosting_password = "xxx" + push_password = "xxx" +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/host/Config.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,33 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Io = require "luan:Io.luan" +local String = require "luan:String.luan" +local regex = String.regex or error() +require "java" +local BackupIndexWriter = require "java:goodjava.lucene.backup.BackupIndexWriter" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "host/Config" + +local this = (...) +local base = regex("^(.*)\Q/host/Config.luan\E$").match(this) or error() +local Admin_config = require(base.."/Config.luan") + + +local Config = {} + +Config.password = Admin_config.hosting_password or error() +Config.old_password = "password" + +local my_ips = Io.my_ips() +if my_ips[Io.ip("s1.luan.software")]==true then + BackupIndexWriter.backupDomains = {"backup.luan.software"} +elseif my_ips[Io.ip("s2.luan.software")]==true then + BackupIndexWriter.backupDomains = {"backup.luan.software"} +else + local dir = Io.uri("file:.").canonical().to_string() + if String.starts_with( dir, "/Users/fschmidt/" ) then + BackupIndexWriter.backupDomains = {"localhost"} + end +end + +return Config
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/lib/Utils.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,77 @@ +local Config = require "site:/private/Config.luan" +local Hosted = require "luan:host/Hosted.luan" +Hosted.no_security and Hosted.no_security(Config.hosting_password) +require "java" +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local Io = require "luan:Io.luan" +local uri = Io.uri or error() +local String = require "luan:String.luan" +local regex = String.regex or error() +local sub_string = String.sub or error() +local Http = require "luan:http/Http.luan" +local Mail = require "luan:mail/Mail.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "Utils" + + +local Utils = {} + +Utils.domain = Http.domain or "admin.me.luan.software" + +Utils.server_domain = regex([[^admin\.(\w+\Q.luan.software\E)$]]).matches(Utils.domain) or error "invalid domain" + +Utils.sites_dir = uri(Http.dir).parent().parent() + +local send = Mail.sender{ + host = "mail.smtp2go.com" + port = 465 + username = "luan.admin2" + password = Config.mail_password or error() +}.send + +function Utils.send_mail(mail) + mail.From = mail.From or Utils.domain.."<monitor@luan.software>" + mail.To = mail.To or Config.email_to or error() + send(mail) +end + +function Utils.ssh(host,cmd) + local cmd = "ssh -t -oConnectTimeout=10 -oServerAliveInterval=10 -oBatchMode=yes -oStrictHostKeyChecking=no -p 14299 administrator@"..host.." '"..cmd.."'" + local con = uri("bash:"..cmd) + return con.read_text() +end + +local function last_modified_in_dir(dir) + local rtn = 0 + for _, child in ipairs(dir.children()) do + local lm = nil + if child.is_directory() then + lm = last_modified_in_dir(child) + elseif child.is_file() then + lm = child.last_modified() + end + if lm ~= nil and lm > rtn then + rtn = lm + end + end + return rtn +end +Utils.last_modified_in_dir = last_modified_in_dir + + +local luanhost_logs = uri "site:/private/local/logs/luanhost" +if not luanhost_logs.exists() then + local logs = uri("file:logs").canonical() + --logs.mkdir() -- must exist + if logs.exists() then + logs.symlink_from(luanhost_logs) + logger.info "linked to luanhost logs" + else + logger.error("logs dir doesn't exist") + end +end + + +return Utils
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/lib/monitor.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,82 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Io = require "luan:Io.luan" +local uri = Io.uri or error() +local String = require "luan:String.luan" +local trim = String.trim or error() +local Time = require "luan:Time.luan" +local Thread = require "luan:Thread.luan" +local Http = require "luan:http/Http.luan" +local Config = require "site:/private/Config.luan" +local Utils = require "site:/private/lib/Utils.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "monitor" + + +local who_monitors_who = { + -- ["admin.me.luan.software"] = "admin.me.luan.software" + ["admin.s1.luan.software"] = "admin.s2.luan.software" + ["admin.s2.luan.software"] = "admin.s1.luan.software" +} +local frequency = Time.period{minutes=2} + +--[[ -- for development +--who_monitors_who["admin.me.luan.software"] = "admin.me.luan.software" +frequency = Time.period{seconds=20} +Config.email_to = "fschmidt@gmail.com" +--]] + + + +local domain = who_monitors_who[Utils.domain] + +if domain == nil then + logger.info "nothing to monitor" + return true +end + +local url = "https://"..domain.."/hi" +local options = { time_out = Time.period{seconds=20} } + +local function init_check() + local fails = 0 + + return function() + try + local page = uri(url,options).read_text() + fails = 0 + logger.info(domain.." is okay") + catch e + logger.error("Error connecting to "..domain..": "..e.get_message()) + fails = fails + 1 + if fails < 2 then return end + try + local s = Utils.ssh(domain,"/Users/administrator/luan/host/restart.sh monitoring") + if trim(s) == "stopped with stop script" then + logger.info("stopped with stop script") + else + logger.error("restart successful\n"..s) + Utils.send_mail { + Subject = domain.." restarted" + body = s + } + end + fails = 0 + catch e + logger.error("restart failed: "..e.get_message()) + if fails < 5 then + Utils.send_mail { + Subject = domain.." restart failed" + body = e.get_message() + } + end + end + end + end +end + +Thread.schedule_closure(init_check,{repeating_delay=frequency}) + +logger.info("monitoring "..domain) + +return true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/admin.html.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,70 @@ +require "site:/init.luan" +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Io = require "luan:Io.luan" +local uri = Io.uri or error() +local String = require "luan:String.luan" +local Http = require "luan:http/Http.luan" +require "java" +local Runtime = require "java:java.lang.Runtime" +local System = require "java:java.lang.System" +local Server = require "java:goodjava.webserver.Server" + + +return function() + local action = Http.request.parameters.action + if action == "gc" then + System.gc() + Http.response.send_redirect "admin.html" + return + end + + Io.stdout = Http.response.text_writer() + + local oneMega = 1024 * 1024; + local free = Runtime.getRuntime().freeMemory() / oneMega; + local total = Runtime.getRuntime().totalMemory() / oneMega; + local used = total - free; + + local loadAverage = uri("os:uptime").read_text() + --local loadAverage = new String(result).replaceAll(".*average:",""); + + local threadPool = Server.threadPool + local threads = threadPool.getPoolSize() + local active_threads = threadPool.getActiveCount() +%> +<!doctype html> +<html lang="en"> + <body> + + <table> + <tr> + <td>Free Memory</td> + <td> + <%=String.format("%.2f",free)%> Mb + </td> + </tr> + <tr> + <td>Used Memory</td> + <td><%=String.format("%.2f",used)%> Mb</td> + </tr> + <tr> + <td>Total Memory</td> + <td><%=String.format("%.2f",total)%> Mb</td> + </tr> + <tr> + <td>Load Average</td> + <td><%=loadAverage%></td> + </tr> + <tr> + <td>Threads</td> + <td><%= active_threads %> active, <%= threads - active_threads %> idle</td> + </tr> + <table> + + <p><a href="admin.html?action=gc">Run GC</a></p> + + </body> +</html> +<% +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/clean_logs.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,31 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local String = require "luan:String.luan" +local regex = String.regex or error() +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local Utils = require "site:/private/lib/Utils.luan" + + +local web_log_regex = regex[[^web.*\.log$]] + +return function() + Http.response.headers["content-type"] = "text/plain" + Io.stdout = Http.response.text_writer() + local dirs = Utils.sites_dir.children() + for _, site_dir in ipairs(dirs) do + local log_dir = site_dir.child("site/private/local/logs") + if log_dir.exists() then + log_dir.child("luan.log").delete() + for _, f in ipairs(log_dir.children()) do + if web_log_regex.matches(f.name()) then + f.delete() + end_if + end_for + end_if + end_for +%> +done +<% +end_function
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/java_threads.html.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,1 @@ +return require("luan:http/tools/Java_threads.luan").respond
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/links.html Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,32 @@ +<!doctype html> +<html lang="en"> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + </head> + <body> + <h1>Links</h1> + <p><a href="https://luanhost.luan.software/">forum</a></p> + <p> + <a href="https://admin.s1.luan.software/">admin.s1.luan.software</a> + - <a href="https://admin.test.luan.software/">admin.test.luan.software</a> + - <a href="https://admin.me.luan.software/">admin.me.luan.software</a> + - private: admin / VU8-ZbbR!=qUQ5V + </p> + <p> + <a href="https://www.luan.software/">luan</a> + - i73tTmyS + </p> + <p> + <a href="https://hg.reactionary.software/repo/luanhost">hg</a> + - <a href="https://hg.luan.software/hghost">hghost</a> + </p> + <p> + <a href="https://internetbs.net/">DNS</a> + - fschmidt@gmail.com / ibs123 + </p> + <p> + <a href="https://www.smtp2go.com/">smtp2go</a> + - fschmidt@luan.software / r2r8gxJTS + </p> + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/luan_threads.html.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,1 @@ +return require("luan:http/tools/Luan_threads.luan").respond
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/request.txt.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,12 @@ +local Binary = require "luan:Binary.luan" +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" + + +return function() + Io.stdout = Http.response.text_writer() + %><%= Http.request.raw_head %><% + if Http.request.body ~= nil then + %><%=Binary.to_string(Http.request.body,"utf-8")%><% + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/run.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,1 @@ +return require("luan:http/tools/Run.luan").respond
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/shell.html.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,1 @@ +return require("luan:http/tools/Shell.luan").respond
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/admin/src/private/tools/sites.html.luan Fri Jul 04 10:25:38 2025 -0600 @@ -0,0 +1,95 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local Io = require "luan:Io.luan" +local String = require "luan:String.luan" +local split = String.split or error() +local Table = require "luan:Table.luan" +local concat = Table.concat or error() +local insert = Table.insert or error() +local sort = Table.sort or error() +local Time = require "luan:Time.luan" +local format_time = Time.format or error() +local Http = require "luan:http/Http.luan" +local Utils = require "site:/private/lib/Utils.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "sites.html" + + +local function remove() + local site = Http.request.parameters.site or error() + local site_dir = Utils.sites_dir.child(site) + site_dir.exists() or error() + site_dir.delete() +end + + +return function() + local action = Http.request.parameters.action + if action == "remove" then + remove() + Http.response.send_redirect "sites.html" + return + end + + Io.stdout = Http.response.text_writer() + local dirs = Utils.sites_dir.children() + for _, dir in ipairs(dirs) do + local t = {} + for _, s in ipairs{split(dir.name(),".")} do + insert(t,1,s) + end + dir.sort = concat(t,".") + end + sort(dirs,function(d1,d2) + return d1.sort < d2.sort + end) +%> +<!doctype html> +<html lang="en"> + <body> + <table> + <tr><th></th><th>site</th><th>logs/web</th><th>DNS</th><th></th><th>password</th></tr> +<% + local my_ips = Io.my_ips() + for i, site_dir in ipairs(dirs) do + local site = site_dir.name() + if site_dir.is_directory() then + local url = "http://"..site + local port = Http.request.port + if port ~= nil and port ~= 80 then + url = url..":"..port + end + url = url.."/" + local password = Luan.do_file(site_dir.to_string().."/info.luan").password or error() + local web_log = site_dir.child("site/private/local/logs/web") + local date = web_log.last_modified() + + local dns = "" + local ip = Io.ip(site) + if my_ips[ip] ~= true then + dns = ip or "not found" + end +%> + <tr> + <td><%=i%></td> + <td><a href="<%=url%>"><%=site%></a></td> + <td nowrap><%=format_time(date,"yyyy-MM-dd")%></td> + <td><%=dns%></td> + <td><a href="sites.html?action=remove&site=<%=site%>" onclick="return confirm('Delete <%=site%>?')">remove</a></td> + <td><%=password%></td> + </tr> +<% + else +%> + <tr><td><%=site%></td></tr> +<% + end + end +%> + <table> + + </body> +</html> +<% +end