mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
feat(devcontainer): multi node
This commit is contained in:
parent
c85a570396
commit
b090564a34
14 changed files with 150 additions and 49 deletions
|
@ -13,15 +13,7 @@ RUN apt-get update && \
|
|||
\
|
||||
# Update package information and install Nginx
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nginx && \
|
||||
\
|
||||
# Install the latest Node.js via NodeSource setup script
|
||||
curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \
|
||||
apt-get update && \
|
||||
apt-get install -y nodejs && \
|
||||
\
|
||||
# Install pnpm globally using npm
|
||||
npm install -g pnpm && \
|
||||
apt-get install -y --no-install-recommends nginx inotify-tools file && \
|
||||
\
|
||||
# Automatically retrieve the latest stable Go version and install it,
|
||||
# download the appropriate binary based on system architecture (amd64 or arm64)
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"features": {
|
||||
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||
"installOhMyZsh": true
|
||||
}
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node:1": {}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
|
@ -27,7 +28,8 @@
|
|||
"antfu.unocss",
|
||||
"github.copilot",
|
||||
"golang.go",
|
||||
"vue.volar"
|
||||
"vue.volar",
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,15 +1,31 @@
|
|||
services:
|
||||
nginx-ui:
|
||||
build: .
|
||||
image: nginx-ui-dev
|
||||
container_name: nginx-ui
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
- ./go-path:/root/go
|
||||
- ./nginx:/etc/nginx
|
||||
- ./data/nginx:/etc/nginx
|
||||
command: sleep infinity
|
||||
environment:
|
||||
- NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
|
||||
networks:
|
||||
nginxui:
|
||||
nginx-ui-2:
|
||||
image: nginx-ui-dev
|
||||
container_name: nginx-ui-2
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
- ./data/nginx-ui-2/nginx:/etc/nginx
|
||||
- ./data/nginx-ui-2/nginx-ui:/etc/nginx-ui
|
||||
working_dir: /workspaces/nginx-ui
|
||||
command: ./.devcontainer/node-supervisor.sh
|
||||
depends_on:
|
||||
- nginx-ui
|
||||
networks:
|
||||
nginxui:
|
||||
|
||||
pebble:
|
||||
image: ghcr.io/letsencrypt/pebble:latest
|
||||
volumes:
|
||||
|
|
6
.devcontainer/init-nginx.sh
Executable file
6
.devcontainer/init-nginx.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
# init nginx config dir
|
||||
if [ "$(ls -A /etc/nginx)" = "" ]; then
|
||||
echo "Initialing Nginx config dir"
|
||||
cp -rp /etc/nginx.orig/* /etc/nginx/
|
||||
echo "Initialed Nginx config dir"
|
||||
fi
|
87
.devcontainer/node-supervisor.sh
Executable file
87
.devcontainer/node-supervisor.sh
Executable file
|
@ -0,0 +1,87 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Configurable variables
|
||||
SOURCE_FILE=/workspaces/nginx-ui/tmp/main
|
||||
TARGET_PATH=/usr/local/bin/nginx-ui
|
||||
CONFIG_FILE=/etc/nginx-ui/app.ini
|
||||
|
||||
# init nginx
|
||||
./.devcontainer/init-nginx.sh
|
||||
|
||||
LOG_PREFIX="[Supervisor]"
|
||||
|
||||
# Debug initial state
|
||||
echo "$LOG_PREFIX Starting supervisor with:"
|
||||
echo "$LOG_PREFIX SOURCE_FILE: $SOURCE_FILE"
|
||||
echo "$LOG_PREFIX TARGET_PATH: $TARGET_PATH"
|
||||
echo "$LOG_PREFIX CONFIG_FILE: $CONFIG_FILE"
|
||||
|
||||
# Wait for initial file creation
|
||||
while [[ ! -f "$SOURCE_FILE" ]]; do
|
||||
echo "$LOG_PREFIX Waiting for $SOURCE_FILE to be created..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Initial copy and start
|
||||
echo "$LOG_PREFIX Initial file detected, starting service..."
|
||||
cp -fv "$SOURCE_FILE" "$TARGET_PATH"
|
||||
chmod +x "$TARGET_PATH"
|
||||
pkill -x nginx-ui || echo "$LOG_PREFIX No existing process to kill"
|
||||
nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 &
|
||||
|
||||
# Use proper field separation for inotify output
|
||||
inotifywait -m -e close_write,moved_to,create,delete \
|
||||
--format "%T|%w%f|%e" \
|
||||
--timefmt "%F-%H:%M:%S" \
|
||||
"$(dirname "$SOURCE_FILE")" |
|
||||
while IFS='|' read -r TIME FILE EVENT; do
|
||||
echo "$LOG_PREFIX [${TIME}] Event: ${EVENT} - ${FILE}"
|
||||
|
||||
# Handle atomic save operations
|
||||
if [[ "$FILE" =~ .*-tmp-umask$ ]] || [[ "$EVENT" == "DELETE" ]]; then
|
||||
echo "$LOG_PREFIX Detected build intermediate file, checking main..."
|
||||
sleep 0.3 # Allow atomic replace completion
|
||||
|
||||
if [[ -f "$SOURCE_FILE" ]]; then
|
||||
echo "$LOG_PREFIX Valid main file detected after build"
|
||||
FILE="$SOURCE_FILE"
|
||||
else
|
||||
echo "$LOG_PREFIX Main file missing after build operation"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$FILE" == "$SOURCE_FILE" ]]; then
|
||||
# Stability checks
|
||||
echo "$LOG_PREFIX File metadata:"
|
||||
ls -l "$FILE"
|
||||
file "$FILE"
|
||||
|
||||
# Wait for file stability with retries
|
||||
retries=5
|
||||
while ((retries-- > 0)); do
|
||||
if file "$FILE" | grep -q "executable"; then
|
||||
break
|
||||
fi
|
||||
echo "$LOG_PREFIX Waiting for valid executable (${retries} retries left)..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if ((retries <= 0)); then
|
||||
echo "$LOG_PREFIX ERROR: File validation failed after 5 retries"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Copy and restart service
|
||||
echo "$LOG_PREFIX Updating service..."
|
||||
cp -fv "$FILE" "$TARGET_PATH"
|
||||
chmod +x "$TARGET_PATH"
|
||||
|
||||
echo "$LOG_PREFIX Killing existing process..."
|
||||
pkill -x nginx-ui || echo "$LOG_PREFIX No process to kill"
|
||||
|
||||
echo "$LOG_PREFIX Starting new process..."
|
||||
nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 &
|
||||
echo "$LOG_PREFIX Restart complete. New PID: $(pgrep nginx-ui)"
|
||||
fi
|
||||
done
|
|
@ -9,11 +9,7 @@ if ! grep -q "zsh-autosuggestions" ~/.zshrc; then
|
|||
fi
|
||||
|
||||
# init nginx config dir
|
||||
if [ "$(ls -A /etc/nginx)" = "" ]; then
|
||||
echo "Initialing Nginx config dir"
|
||||
cp -rp /etc/nginx.orig/* /etc/nginx/
|
||||
echo "Initialed Nginx config dir"
|
||||
fi
|
||||
./.devcontainer/init-nginx.sh
|
||||
|
||||
# install app dependencies
|
||||
echo "Installing app dependencies"
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -15,5 +15,5 @@ app/.status_hash
|
|||
.idea/deployment.xml
|
||||
.idea/webServers.xml
|
||||
.devcontainer/go-path
|
||||
.devcontainer/nginx
|
||||
.devcontainer/data
|
||||
.devcontainer/casdoor.pem
|
||||
|
|
|
@ -4,6 +4,10 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||
"github.com/0xJacky/Nginx-UI/internal/cluster"
|
||||
|
@ -14,9 +18,6 @@ import (
|
|||
"github.com/spf13/cast"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetEnvironment(c *gin.Context) {
|
||||
|
@ -151,23 +152,10 @@ func EditEnvironment(c *gin.Context) {
|
|||
}
|
||||
|
||||
func DeleteEnvironment(c *gin.Context) {
|
||||
id := cast.ToUint64(c.Param("id"))
|
||||
envQuery := query.Environment
|
||||
|
||||
env, err := envQuery.FirstByID(id)
|
||||
if err != nil {
|
||||
api.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
err = envQuery.DeleteByID(env.ID)
|
||||
if err != nil {
|
||||
api.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
go analytic.RestartRetrieveNodesStatus()
|
||||
|
||||
c.JSON(http.StatusNoContent, nil)
|
||||
cosy.Core[model.Environment](c).
|
||||
ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
|
||||
go analytic.RestartRetrieveNodesStatus()
|
||||
}).Destroy()
|
||||
}
|
||||
|
||||
func LoadEnvironmentFromSettings(c *gin.Context) {
|
||||
|
|
|
@ -181,7 +181,7 @@ function handleBatchUpdated() {
|
|||
v-if="!disableAdd && !inTrash"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="add"
|
||||
@click="add()"
|
||||
>
|
||||
{{ $gettext('Add') }}
|
||||
</AButton>
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":"2.0.0-rc.1","build_id":1,"total_build":375}
|
||||
{"version":"2.0.0-rc.1","build_id":7,"total_build":381}
|
|
@ -6,6 +6,7 @@ import BatchUpgrader from '@/views/environment/BatchUpgrader.vue'
|
|||
import envColumns from '@/views/environment/envColumns'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
const route = useRoute()
|
||||
const curd = ref()
|
||||
function loadFromSettings() {
|
||||
environment.load_from_settings().then(() => {
|
||||
|
@ -20,6 +21,18 @@ const refUpgrader = ref()
|
|||
function batchUpgrade() {
|
||||
refUpgrader.value.open(selectedNodeIds, selectedNodes)
|
||||
}
|
||||
|
||||
const inTrash = computed(() => {
|
||||
return route.query.trash === 'true'
|
||||
})
|
||||
|
||||
// const timer = setInterval(() => {
|
||||
// curd.value.get_list()
|
||||
// }, 10000)
|
||||
|
||||
// onUnmounted(() => {
|
||||
// clearInterval(timer)
|
||||
// })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -43,7 +56,7 @@ function batchUpgrade() {
|
|||
|
||||
<BatchUpgrader ref="refUpgrader" />
|
||||
|
||||
<FooterToolBar>
|
||||
<FooterToolBar v-if="!inTrash">
|
||||
<ATooltip
|
||||
:title="$gettext('Please select at least one node to upgrade')"
|
||||
placement="topLeft"
|
||||
|
|
|
@ -26,12 +26,12 @@ const columns: Column[] = [{
|
|||
placeholder: () => 'https://10.0.0.1:9000',
|
||||
},
|
||||
},
|
||||
width: 300,
|
||||
width: 260,
|
||||
}, {
|
||||
title: () => $gettext('Version'),
|
||||
dataIndex: 'version',
|
||||
pithy: true,
|
||||
width: 150,
|
||||
width: 120,
|
||||
}, {
|
||||
title: () => 'NodeSecret',
|
||||
dataIndex: 'token',
|
||||
|
@ -65,7 +65,7 @@ const columns: Column[] = [{
|
|||
},
|
||||
sorter: true,
|
||||
pithy: true,
|
||||
width: 200,
|
||||
width: 120,
|
||||
}, {
|
||||
title: () => $gettext('Enabled'),
|
||||
dataIndex: 'enabled',
|
||||
|
@ -85,7 +85,7 @@ const columns: Column[] = [{
|
|||
},
|
||||
sorter: true,
|
||||
pithy: true,
|
||||
width: 150,
|
||||
width: 120,
|
||||
}, {
|
||||
title: () => $gettext('Updated at'),
|
||||
dataIndex: 'updated_at',
|
||||
|
|
7
main.go
7
main.go
|
@ -1,22 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/kernel"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/0xJacky/Nginx-UI/router"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jpillora/overseer"
|
||||
"errors"
|
||||
"github.com/uozi-tech/cosy"
|
||||
cKernel "github.com/uozi-tech/cosy/kernel"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
cRouter "github.com/uozi-tech/cosy/router"
|
||||
cSettings "github.com/uozi-tech/cosy/settings"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Program(confPath string) func(state overseer.State) {
|
||||
|
|
|
@ -10,7 +10,7 @@ type Environment struct {
|
|||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Token string `json:"token"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
Enabled bool `json:"enabled" gorm:"default:false"`
|
||||
}
|
||||
|
||||
func (e *Environment) GetUrl(uri string) (decodedUri string, err error) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue