diff --git a/applications/luci-app-heimdall/Makefile b/applications/luci-app-heimdall/Makefile new file mode 100644 index 0000000..d0f1850 --- /dev/null +++ b/applications/luci-app-heimdall/Makefile @@ -0,0 +1,19 @@ + + +include $(TOPDIR)/rules.mk + +PKG_VERSION:=1.0.0 +PKG_RELEASE:=20220629 + +LUCI_TITLE:=LuCI support for heimdall +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+docker +luci-lib-iform + +define Package/luci-app-heimdall/conffiles +/etc/config/heimdall +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature + diff --git a/applications/luci-app-heimdall/luasrc/controller/heimdall.lua b/applications/luci-app-heimdall/luasrc/controller/heimdall.lua new file mode 100755 index 0000000..8d72c48 --- /dev/null +++ b/applications/luci-app-heimdall/luasrc/controller/heimdall.lua @@ -0,0 +1,287 @@ +local util = require "luci.util" +local http = require "luci.http" +local iform = require "luci.iform" +local jsonc = require "luci.jsonc" + +module("luci.controller.heimdall", package.seeall) + +function index() + + entry({"admin", "services", "heimdall"}, call("redirect_index"), _("Heimdall"), 30).dependent = true + entry({"admin", "services", "heimdall", "pages"}, call("heimdall_index")).leaf = true + entry({"admin", "services", "heimdall", "form"}, call("heimdall_form")) + entry({"admin", "services", "heimdall", "submit"}, call("heimdall_submit")) + entry({"admin", "services", "heimdall", "log"}, call("heimdall_log")) + +end + +local const_log_end = "XU6J03M6" +local appname = "heimdall" +local page_index = {"admin", "services", "heimdall", "pages"} + +function redirect_index() + http.redirect(luci.dispatcher.build_url(unpack(page_index))) +end + +function heimdall_index() + luci.template.render("heimdall/main", {prefix=luci.dispatcher.build_url(unpack(page_index))}) +end + +function heimdall_form() + local error = "" + local scope = "" + local success = 0 + + local data = get_data() + local result = { + data = data, + schema = get_schema(data) + } + local response = { + error = error, + scope = scope, + success = success, + result = result, + } + http.prepare_content("application/json") + http.write_json(response) +end + +function get_schema(data) + local actions + if data.container_install then + actions = { + { + name = "restart", + text = "重启", + type = "apply", + }, + { + name = "upgrade", + text = "更新", + type = "apply", + }, + { + name = "remove", + text = "删除", + type = "apply", + }, + } + else + actions = { + { + name = "install", + text = "安装", + type = "apply", + }, + } + end + local _ = luci.i18n.translate + local access = _('access homepage: ') + local homepage = 'Heimdall' + local schema = { + actions = actions, + containers = get_containers(data), + description = _("Heimdall is an elegant solution to organise all your web applications.")..access..homepage, + title = _("Heimdall") + } + return schema +end + +function get_containers(data) + local containers = { + status_container(data), + main_container(data) + } + return containers +end + +function status_container(data) + local status_value + + if data.container_install then + status_value = "Heimdall 运行中" + else + status_value = "Heimdall 未运行" + end + + local status_c1 = { + labels = { + { + key = "状态:", + value = status_value + }, + { + key = "访问:", + value = "" + } + + }, + description = "Heimdall 的状态信息如下:", + title = "服务状态" + } + return status_c1 +end + +function main_container(data) + local main_c2 = { + properties = { + { + name = "http_port", + required = true, + title = "HTTP 端口", + type = "string" + }, + { + name = "https_port", + required = true, + title = "HTTPS 端口", + type = "string" + }, + { + name = "config_path", + required = true, + title = "配置路径:", + type = "string", + enum = dup_to_enums(data.blocks), + enumNames = dup_to_enums(data.blocks) + }, + }, + description = "请选择合适的配置路径进行安装:", + title = "服务操作" + } + return main_c2 +end + +function get_data() + local uci = require "luci.model.uci".cursor() + local default_path = "" + local blks = blocks() + if #blks > 0 then + default_path = blks[1] .. "/heimdall" + end + local blk1 = {} + for _, val in pairs(blks) do + table.insert(blk1, val .. "/heimdall") + end + local docker_path = util.exec("which docker") + local docker_install = (string.len(docker_path) > 0) + local container_id = util.trim(util.exec("docker ps -qf 'name="..appname.."'")) + local container_install = (string.len(container_id) > 0) + local http_port = tonumber(uci:get_first(appname, appname, "http_port", "8088")) + local https_port = tonumber(uci:get_first(appname, appname, "https_port", "8089")) + local data = { + http_port = http_port, + https_port = https_port, + lang = uci:get_first(appname, appname, "lang", "en"), + config_path = uci:get_first(appname, appname, "config_path", default_path), + blocks = blk1, + container_install = container_install + } + return data +end + +function heimdall_submit() + local error = "" + local scope = "" + local success = 0 + local result + + local json_parse = jsonc.parse + local content = http.content() + local req = json_parse(content) + if req["$apply"] == "upgrade" then + result = install_upgrade_heimdall(req) + elseif req["$apply"] == "install" then + result = install_upgrade_heimdall(req) + elseif req["$apply"] == "restart" then + result = restart_heimdall(req) + else + result = delete_heimdall() + end + http.prepare_content("application/json") + local resp = { + error = error, + scope = scope, + success = success, + result = result, + } + http.write_json(resp) +end + +function heimdall_log() + iform.response_log("/var/log/"..appname..".log") +end + +function install_upgrade_heimdall(req) + local http_port = req["http_port"] + local https_port = req["https_port"] + + -- save config + local uci = require "luci.model.uci".cursor() + uci:tset(appname, "@"..appname.."[0]", { + http_port = http_port or "8088", + https_port = https_port or "8089", + lang = req["lang"], + config_path = req["config_path"], + }) + uci:save(appname) + uci:commit(appname) + + local exec_cmd = string.format("/usr/share/heimdall/install.sh %s", req["$apply"]) + iform.fork_exec(exec_cmd) + + local result = { + async = true, + exec = exec_cmd, + async_state = req["$apply"] + } + return result +end + +function delete_heimdall() + local log = iform.exec_to_log("docker rm -f heimdall") + local result = { + async = false, + log = log + } + return result +end + +function restart_heimdall() + local log = iform.exec_to_log("docker restart heimdall") + local result = { + async = false, + log = log + } + return result +end + +function blocks() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj["blockdevices"]) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + -- fsize > 1G + vals[#vals+1] = val["mountpoint"] + end + end + end + return vals +end + +function dup_to_enums(a) + if #a == 0 then + return nil + end + local a2 = {} + for _, val in pairs(a) do + table.insert(a2, val) + end + return a2 +end diff --git a/applications/luci-app-heimdall/luasrc/view/heimdall/main.htm b/applications/luci-app-heimdall/luasrc/view/heimdall/main.htm new file mode 100644 index 0000000..1617eae --- /dev/null +++ b/applications/luci-app-heimdall/luasrc/view/heimdall/main.htm @@ -0,0 +1,33 @@ +<%+header%> + + +
+
+ + + + + +<%+footer%> diff --git a/applications/luci-app-heimdall/po/zh-cn/heimdall.po b/applications/luci-app-heimdall/po/zh-cn/heimdall.po new file mode 100644 index 0000000..f8c974c --- /dev/null +++ b/applications/luci-app-heimdall/po/zh-cn/heimdall.po @@ -0,0 +1,2 @@ +msgid "heimdall" +msgstr "Heimdall 精美导航" diff --git a/applications/luci-app-heimdall/root/etc/config/heimdall b/applications/luci-app-heimdall/root/etc/config/heimdall new file mode 100644 index 0000000..667b01a --- /dev/null +++ b/applications/luci-app-heimdall/root/etc/config/heimdall @@ -0,0 +1,6 @@ +config heimdall + option 'config_path' '' + option 'http_port' '8088' + option 'https_port' '8089' + option 'lang' '' + diff --git a/applications/luci-app-heimdall/root/usr/share/heimdall/install.sh b/applications/luci-app-heimdall/root/usr/share/heimdall/install.sh new file mode 100755 index 0000000..f94c506 --- /dev/null +++ b/applications/luci-app-heimdall/root/usr/share/heimdall/install.sh @@ -0,0 +1,118 @@ +#!/bin/sh +# Author Xiaobao(xiaobao@linkease.com) + +ACTION=${1} +WRLOCK=/var/lock/heimdall.lock +LOGFILE=/var/log/heimdall.log +LOGEND="XU6J03M6" +shift 1 + +IMAGE_NAME='lscr.io/linuxserver/heimdall:latest' + +check_params() { + + if [ -z "${WRLOCK}" ]; then + echo "lock file not found" + exit 1 + fi + + if [ -z "${LOGFILE}" ]; then + echo "logger file not found" + exit 1 + fi + +} + +lock_run() { + local lock="$WRLOCK" + exec 300>$lock + flock -n 300 || return + do_run + flock -u 300 + return +} + +run_action() { + if check_params; then + lock_run + fi +} + +do_install() { + local CONFIG_PATH=`uci get heimdall.@heimdall[0].config_path 2>/dev/null` + local HTTP_PORT=`uci get heimdall.@heimdall[0].http_port 2>/dev/null` + local HTTPS_PORT=`uci get heimdall.@heimdall[0].https_port 2>/dev/null` + local LANG=`uci get heimdall.@heimdall[0].lang 2>/dev/null` + if [ -z "${CONFIG_PATH}" ]; then + echo "config path is empty!" >${LOGFILE} + exit 1 + fi + if [ -z "${HTTP_PORT}" ]; then + HTTP_PORT=8088 + fi + if [ -z "${HTTPS_PORT}" ]; then + HTTPS_PORT=8089 + fi + echo "docker pull ${IMAGE_NAME}" >${LOGFILE} + docker pull ${IMAGE_NAME} >>${LOGFILE} 2>&1 + docker rm -f heimdall + local mntv="/mnt:/mnt" + mountpoint -q /mnt && mntv="$mntv:rslave" + docker run -d \ + --name=heimdall \ + -e TZ=Asia/Shanghai \ + -p ${HTTP_PORT}:80 \ + -p ${HTTPS_PORT}:443 \ + -v ${CONFIG_PATH}:/config -v ${mntv} \ + --restart unless-stopped \ + $IMAGE_NAME >>${LOGFILE} 2>&1 + + RET=$? + if [ "${RET}" = "0" ]; then + # mark END, remove the log file + echo ${LOGEND} >> ${LOGFILE} + sleep 5 + rm -f ${LOGFILE} + else + # reserve the log + echo "docker run ${IMAGE_NAME} failed" >>${LOGFILE} + echo ${LOGEND} >> ${LOGFILE} + fi + exit ${RET} +} + +# run in lock +do_run() { + case ${ACTION} in + "install") + do_install + ;; + "upgrade") + do_install + ;; + esac +} + +usage() { + echo "usage: wxedge sub-command" + echo "where sub-command is one of:" + echo " install Install the heimdall" + echo " upgrade Upgrade the heimdall" + echo " remove Remove the heimdall" +} + +case ${ACTION} in + "install") + run_action + ;; + "upgrade") + run_action + ;; + "remove") + docker rm -f heimdall + ;; + *) + usage + ;; +esac +