mirror of
https://github.com/AlbrechtL/openwrt-docker.git
synced 2026-10-27 00:00:59 +00:00
Add web interface button for restart and factory reset
This commit is contained in:
@@ -12,11 +12,14 @@ RUN apk add --no-cache \
|
||||
qemu-hw-usb-host \
|
||||
qemu-hw-usb-redirect \
|
||||
nginx \
|
||||
netcat-openbsd \
|
||||
&& mkdir -p /usr/share/novnc \
|
||||
&& wget https://github.com/novnc/noVNC/archive/refs/tags/v${NOVNC_VERSION}.tar.gz -O /tmp/novnc.tar.gz -q \
|
||||
&& tar -xf /tmp/novnc.tar.gz -C /tmp/ \
|
||||
&& cd /tmp/noVNC-${NOVNC_VERSION}\
|
||||
&& mv app core vendor package.json *.html /usr/share/novnc \
|
||||
&& wget https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_arm64.apk \
|
||||
&& apk add --allow-untrusted OliveTin_linux_arm64.apk \
|
||||
&& sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf
|
||||
|
||||
# export OPENWRT_VERSION=`date '+%Y%M%W'`_$OPENWRT_VERSION \
|
||||
|
||||
+3
-2
@@ -139,7 +139,7 @@ if [ -f /storage/old_version ]; then
|
||||
chmod +x /mnt/etc/rc.local
|
||||
umount /mnt
|
||||
|
||||
info "Boot previos $OLD_VERSION_ROOTFS to get config"
|
||||
info "Boot previous $OLD_VERSION_ROOTFS to get config"
|
||||
qemu-system-aarch64 -M virt \
|
||||
-m 128 \
|
||||
-nodefaults \
|
||||
@@ -220,7 +220,8 @@ exec qemu-system-aarch64 -M virt \
|
||||
-device qemu-xhci -device usb-kbd \
|
||||
$LAN_ARGS \
|
||||
$WAN_ARGS \
|
||||
$USB_ARGS
|
||||
$USB_ARGS \
|
||||
-qmp unix:/run/qmp-sock,server=on,wait=off
|
||||
|
||||
# -device virtio-net,netdev=qlan1 -netdev user,id=qlan1,net=192.168.1.0/24,hostfwd=tcp::8000-192.168.1.1:80 \
|
||||
# -blockdev driver=raw,node-name=hd0,cache.direct=on,file.driver=file,file.filename=/var/vm/openwrt-armsr-armv8-generic-ext4-combined.img \
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
# Source: https://www.redhat.com/sysadmin/arguments-options-bash-scripts
|
||||
|
||||
VERSION=0.1
|
||||
|
||||
############################################################
|
||||
# Help #
|
||||
############################################################
|
||||
Help()
|
||||
{
|
||||
# Display Help
|
||||
echo "Small helper to interact with qemu QMP"
|
||||
echo
|
||||
echo "Syntax: qemu_qmp [-r|h|v]"
|
||||
echo "options:"
|
||||
echo "r Reset VM."
|
||||
echo "h Print this Help."
|
||||
echo "v Print software version and exit."
|
||||
echo
|
||||
}
|
||||
|
||||
############################################################
|
||||
############################################################
|
||||
# Main program #
|
||||
############################################################
|
||||
############################################################
|
||||
############################################################
|
||||
# Process the input options. Add options as needed. #
|
||||
############################################################
|
||||
# Get the options
|
||||
while getopts ":hvrqf" option; do
|
||||
case $option in
|
||||
h) # display Help
|
||||
Help
|
||||
exit;;
|
||||
v) # Show version
|
||||
echo $VERSION
|
||||
exit;;
|
||||
r) # Reset VM
|
||||
echo -ne '{ "execute": "qmp_capabilities" } { "execute": "system_reset" }' | nc -w 1 -U /run/qmp-sock
|
||||
exit;;
|
||||
q) # Quit Qemu
|
||||
echo -ne '{ "execute": "qmp_capabilities" } { "execute": "quit" }' | nc -w 1 -U /run/qmp-sock
|
||||
exit;;
|
||||
f) # Apply factory reset
|
||||
rm /storage/current_version
|
||||
rm /storage/rootfs-${OPENWRT_VERSION}.img
|
||||
echo -ne '{ "execute": "qmp_capabilities" } { "execute": "quit" }' | nc -w 1 -U /run/qmp-sock
|
||||
exit;;
|
||||
\?) # Invalid option
|
||||
echo "Error: Invalid option"
|
||||
Help
|
||||
exit;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -168,4 +168,8 @@ cp -r /var/www/* /run/shm
|
||||
html "Starting $APP for Docker..."
|
||||
nginx -e stderr
|
||||
|
||||
# Start OliveTin
|
||||
cp -f /var/www/olivetin_config.yaml /etc/OliveTin/config.yaml
|
||||
OliveTin 2> /var/log/olivetin.log &
|
||||
|
||||
return 0
|
||||
|
||||
+10
-152
@@ -1,154 +1,12 @@
|
||||
body {
|
||||
color: white;
|
||||
background-color: #125bdb;
|
||||
font-family: Verdana, Arial, sans-serif;
|
||||
}
|
||||
div {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
html, body, div, iframe { height: 100%; }
|
||||
|
||||
#content {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
iframe {
|
||||
display:inline-block;
|
||||
margin: 5px auto;
|
||||
border: solid;
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 98%;
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
color: #0c8aeb;
|
||||
}
|
||||
|
||||
#empty {
|
||||
height: 40px;
|
||||
/* Same height as footer */
|
||||
}
|
||||
|
||||
a,
|
||||
a:hover,
|
||||
a:active,
|
||||
a:visited {
|
||||
color: white;
|
||||
}
|
||||
|
||||
footer a:link,
|
||||
footer a:visited,
|
||||
footer a:active { color: #0c8aeb; }
|
||||
footer a:hover { color: #73e6ff; }
|
||||
|
||||
.loading:after {
|
||||
content: " .";
|
||||
animation: dots 1s steps(5, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes dots {
|
||||
|
||||
0%,
|
||||
20% {
|
||||
color: rgba(0, 0, 0, 0);
|
||||
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
40% {
|
||||
color: white;
|
||||
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
60% {
|
||||
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
80%,
|
||||
100% {
|
||||
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner_LWk7 {
|
||||
animation: spinner_GWy6 1.2s linear infinite, spinner_BNNO 1.2s linear infinite
|
||||
}
|
||||
|
||||
.spinner_yOMU {
|
||||
animation: spinner_GWy6 1.2s linear infinite, spinner_pVqn 1.2s linear infinite;
|
||||
animation-delay: .15s
|
||||
}
|
||||
|
||||
.spinner_KS4S {
|
||||
animation: spinner_GWy6 1.2s linear infinite, spinner_6uKB 1.2s linear infinite;
|
||||
animation-delay: .3s
|
||||
}
|
||||
|
||||
.spinner_zVee {
|
||||
animation: spinner_GWy6 1.2s linear infinite, spinner_Qw4x 1.2s linear infinite;
|
||||
animation-delay: .45s
|
||||
}
|
||||
|
||||
@keyframes spinner_GWy6 {
|
||||
|
||||
0%,
|
||||
50% {
|
||||
width: 9px;
|
||||
height: 9px
|
||||
}
|
||||
|
||||
10% {
|
||||
width: 11px;
|
||||
height: 11px
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spinner_BNNO {
|
||||
|
||||
0%,
|
||||
50% {
|
||||
x: 1.5px;
|
||||
y: 1.5px
|
||||
}
|
||||
|
||||
10% {
|
||||
x: .5px;
|
||||
y: .5px
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spinner_pVqn {
|
||||
|
||||
0%,
|
||||
50% {
|
||||
x: 13.5px;
|
||||
y: 1.5px
|
||||
}
|
||||
|
||||
10% {
|
||||
x: 12.5px;
|
||||
y: .5px
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spinner_6uKB {
|
||||
|
||||
0%,
|
||||
50% {
|
||||
x: 13.5px;
|
||||
y: 13.5px
|
||||
}
|
||||
|
||||
10% {
|
||||
x: 12.5px;
|
||||
y: 12.5px
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spinner_Qw4x {
|
||||
|
||||
0%,
|
||||
50% {
|
||||
x: 1.5px;
|
||||
y: 13.5px
|
||||
}
|
||||
|
||||
10% {
|
||||
x: .5px;
|
||||
y: 12.5px
|
||||
}
|
||||
}
|
||||
|
||||
+3
-19
@@ -2,33 +2,17 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
[1]
|
||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.css" />
|
||||
<link rel="icon" href="/img/favicon.svg" type="image/x-icon">
|
||||
[2]
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<svg id="spinner" width="64" height="64" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect class="spinner_LWk7" fill="#0c8aeb" x="1.5" y="1.5" rx="1" width="9" height="9"/>
|
||||
<rect class="spinner_yOMU" fill="#0c8aeb" x="13.5" y="1.5" rx="1" width="9" height="9"/>
|
||||
<rect class="spinner_KS4S" fill="#0c8aeb" x="13.5" y="13.5" rx="1" width="9" height="9"/>
|
||||
<rect class="spinner_zVee" fill="#0c8aeb" x="1.5" y="13.5" rx="1" width="9" height="9"/>
|
||||
</svg>
|
||||
<h1 id="info">[3]</h1>
|
||||
</div>
|
||||
<div id="empty">
|
||||
</div>
|
||||
<footer id="footer">
|
||||
[4]<br />
|
||||
[5]
|
||||
</footer>
|
||||
<div>
|
||||
<iframe src="/olivetin" width="29%"></iframe>
|
||||
<iframe src="/novnc" width="70%"></iframe>
|
||||
</div>
|
||||
<script type="text/javascript" src="/js/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
var request;
|
||||
var interval = 1000;
|
||||
|
||||
function getInfo() {
|
||||
|
||||
var url = "/msg.html";
|
||||
|
||||
try {
|
||||
|
||||
if (window.XMLHttpRequest) {
|
||||
request = new XMLHttpRequest();
|
||||
} else {
|
||||
throw "XMLHttpRequest not available!";
|
||||
}
|
||||
|
||||
request.onreadystatechange = processInfo;
|
||||
request.open("GET", url, true);
|
||||
request.send();
|
||||
|
||||
} catch (e) {
|
||||
var err = "Error: " + e.message;
|
||||
console.log(err);
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
function processInfo() {
|
||||
try {
|
||||
|
||||
if (request.readyState != 4) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var msg = request.responseText;
|
||||
if (msg == null || msg.length == 0) {
|
||||
setError("Lost connection");
|
||||
schedule();
|
||||
return false;
|
||||
}
|
||||
|
||||
var notFound = (request.status == 404);
|
||||
|
||||
if (request.status == 200) {
|
||||
if (msg.toLowerCase().indexOf("<html>") !== -1) {
|
||||
notFound = true;
|
||||
} else {
|
||||
setInfo(msg);
|
||||
schedule();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (notFound) {
|
||||
setInfo("Connecting to VNC", true);
|
||||
reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
setError("Error: Received statuscode " + request.status);
|
||||
schedule();
|
||||
return false;
|
||||
|
||||
} catch (e) {
|
||||
var err = "Error: " + e.message;
|
||||
console.log(err);
|
||||
setError(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setInfo(msg, loading, error) {
|
||||
try {
|
||||
|
||||
if (msg == null || msg.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var el = document.getElementById("spinner");
|
||||
|
||||
error = !!error;
|
||||
if (!error) {
|
||||
el.style.visibility = 'visible';
|
||||
} else {
|
||||
el.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
loading = !!loading;
|
||||
if (loading) {
|
||||
msg = "<p class=\"loading\">" + msg + "</p>";
|
||||
}
|
||||
|
||||
el = document.getElementById("info");
|
||||
|
||||
if (el.innerHTML != msg) {
|
||||
el.innerHTML = msg;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
console.log("Error: " + e.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setError(text) {
|
||||
return setInfo(text, false, true);
|
||||
}
|
||||
|
||||
function schedule() {
|
||||
setTimeout(getInfo, interval);
|
||||
}
|
||||
|
||||
function reload() {
|
||||
setTimeout(() => {
|
||||
document.location.reload();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
schedule();
|
||||
+16
-14
@@ -26,25 +26,17 @@ server {
|
||||
add_header Cache-Control "no-cache";
|
||||
|
||||
location / {
|
||||
|
||||
root /run/shm;
|
||||
|
||||
if ( -f /run/shm/index.html) {
|
||||
break;
|
||||
}
|
||||
|
||||
try_files /index.html @vnc;
|
||||
root /var/www;
|
||||
}
|
||||
|
||||
location @vnc {
|
||||
|
||||
root /usr/share/novnc;
|
||||
location /novnc {
|
||||
index vnc.html;
|
||||
alias /usr/share/novnc;
|
||||
try_files $uri $uri/ /vnc.html;
|
||||
|
||||
if ($request_uri = "/") {
|
||||
return 301 /?resize=scale&autoconnect=true;
|
||||
if ($request_uri = "/novnc/") {
|
||||
return 301 ?resize=scale&autoconnect=true&reconnect_delay=2000&reconnect=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /websockify {
|
||||
@@ -61,4 +53,14 @@ server {
|
||||
proxy_pass http://127.0.0.1:5700/;
|
||||
}
|
||||
|
||||
location /olivetin/ {
|
||||
proxy_pass http://localhost:1337/;
|
||||
proxy_redirect http://localhost:1337/ http://localhost/OliveTin/;
|
||||
}
|
||||
|
||||
location /websocket {
|
||||
proxy_set_header Upgrade "websocket";
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://localhost:1337/websocket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# There is a built-in micro proxy that will host the webui and REST API all on
|
||||
# one port (this is called the "Single HTTP Frontend") and means you just need
|
||||
# one open port in the container/firewalls/etc.
|
||||
#
|
||||
# Listen on all addresses available, port 1337
|
||||
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
|
||||
|
||||
# Choose from INFO (default), WARN and DEBUG
|
||||
logLevel: "INFO"
|
||||
|
||||
# Actions (buttons) to show up on the WebUI:
|
||||
actions:
|
||||
- title: Restart Openwrt
|
||||
shell: /run/qemu_qmp.sh -r
|
||||
icon: restart
|
||||
|
||||
- title: Factory reset
|
||||
shell: /run/qemu_qmp.sh -f
|
||||
icon: "⚙"
|
||||
Reference in New Issue
Block a user