mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
feat: reload cluster node settings from settings file #169
This commit is contained in:
parent
29f1b7db89
commit
e0366f949f
13 changed files with 110 additions and 34 deletions
|
@ -3,9 +3,11 @@ package cluster
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/api"
|
"github.com/0xJacky/Nginx-UI/api"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||||
|
"github.com/0xJacky/Nginx-UI/internal/cluster"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/cosy"
|
"github.com/0xJacky/Nginx-UI/internal/cosy"
|
||||||
"github.com/0xJacky/Nginx-UI/model"
|
"github.com/0xJacky/Nginx-UI/model"
|
||||||
"github.com/0xJacky/Nginx-UI/query"
|
"github.com/0xJacky/Nginx-UI/query"
|
||||||
|
"github.com/0xJacky/Nginx-UI/settings"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -75,3 +77,19 @@ func DeleteEnvironment(c *gin.Context) {
|
||||||
|
|
||||||
c.JSON(http.StatusNoContent, nil)
|
c.JSON(http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadEnvironmentFromSettings(c *gin.Context) {
|
||||||
|
err := settings.ReloadCluster()
|
||||||
|
if err != nil {
|
||||||
|
api.ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.RegisterPredefinedNodes()
|
||||||
|
|
||||||
|
go analytic.RestartRetrieveNodesStatus()
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "ok",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import "github.com/gin-gonic/gin"
|
||||||
func InitRouter(r *gin.RouterGroup) {
|
func InitRouter(r *gin.RouterGroup) {
|
||||||
// Environment
|
// Environment
|
||||||
r.GET("environments", GetEnvironmentList)
|
r.GET("environments", GetEnvironmentList)
|
||||||
|
r.POST("environments/load_from_settings", LoadEnvironmentFromSettings)
|
||||||
envGroup := r.Group("environment")
|
envGroup := r.Group("environment")
|
||||||
{
|
{
|
||||||
envGroup.GET("/:id", GetEnvironment)
|
envGroup.GET("/:id", GetEnvironment)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import en_US from 'ant-design-vue/es/locale/en_US'
|
||||||
|
|
||||||
import { useSettingsStore } from '@/pinia'
|
import { useSettingsStore } from '@/pinia'
|
||||||
import gettext from '@/gettext'
|
import gettext from '@/gettext'
|
||||||
|
import loadTranslations from '@/api/translations'
|
||||||
|
|
||||||
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
|
||||||
|
@ -49,6 +50,8 @@ const lang = computed(() => {
|
||||||
|
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const is_theme_dark = computed(() => settings.theme === 'dark')
|
const is_theme_dark = computed(() => settings.theme === 'dark')
|
||||||
|
|
||||||
|
loadTranslations()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import http from '@/lib/http'
|
||||||
import type { ModelBase } from '@/api/curd'
|
import type { ModelBase } from '@/api/curd'
|
||||||
import Curd from '@/api/curd'
|
import Curd from '@/api/curd'
|
||||||
|
|
||||||
|
@ -14,6 +15,17 @@ export interface Node {
|
||||||
token: string
|
token: string
|
||||||
response_at?: Date
|
response_at?: Date
|
||||||
}
|
}
|
||||||
const environment: Curd<Environment> = new Curd('/environment')
|
|
||||||
|
class EnvironmentCurd extends Curd<Environment> {
|
||||||
|
constructor() {
|
||||||
|
super('/environment')
|
||||||
|
}
|
||||||
|
|
||||||
|
load_from_settings() {
|
||||||
|
return http.post(`${this.plural}/load_from_settings`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const environment: EnvironmentCurd = new EnvironmentCurd()
|
||||||
|
|
||||||
export default environment
|
export default environment
|
||||||
|
|
19
app/src/api/translations.ts
Normal file
19
app/src/api/translations.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import gettext from '@/gettext'
|
||||||
|
|
||||||
|
export default async function loadTranslations() {
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
if (gettext.current !== 'en') {
|
||||||
|
await fetch(`${import.meta.env.VITE_API_ROOT}/translation/${gettext.current}`).then(async r => {
|
||||||
|
gettext.translations[gettext.current] = await r.json()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (route?.meta?.name)
|
||||||
|
document.title = `${route.meta.name?.()} | Nginx UI`
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(route, () => {
|
||||||
|
if (route?.meta?.name)
|
||||||
|
document.title = `${route.meta.name?.()} | Nginx UI`
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,32 +1,27 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue'
|
import { watch } from 'vue'
|
||||||
|
|
||||||
import { useSettingsStore } from '@/pinia'
|
import { useSettingsStore } from '@/pinia'
|
||||||
import http from '@/lib/http'
|
|
||||||
import gettext from '@/gettext'
|
import gettext from '@/gettext'
|
||||||
|
import loadTranslations from '@/api/translations'
|
||||||
|
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const current = ref(gettext.current)
|
const current = computed({
|
||||||
|
get() {
|
||||||
|
return gettext.current
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
gettext.current = v
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const languageAvailable = gettext.available
|
const languageAvailable = gettext.available
|
||||||
|
|
||||||
async function init() {
|
|
||||||
if (current.value !== 'en') {
|
|
||||||
await http.get(`/translation/${current.value}`).then(r => {
|
|
||||||
gettext.translations[current.value] = r
|
|
||||||
})
|
|
||||||
|
|
||||||
document.title = `${route.meta.name?.()} | Nginx UI`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init()
|
|
||||||
|
|
||||||
watch(current, v => {
|
watch(current, v => {
|
||||||
init()
|
loadTranslations()
|
||||||
settings.set_language(v)
|
settings.set_language(v)
|
||||||
gettext.current = v
|
gettext.current = v
|
||||||
|
|
||||||
|
@ -34,7 +29,6 @@ watch(current, v => {
|
||||||
|
|
||||||
document.title = `${name()} | Nginx UI`
|
document.title = `${name()} | Nginx UI`
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { Badge, Tag } from 'ant-design-vue'
|
import { Badge, Tag, message } from 'ant-design-vue'
|
||||||
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
||||||
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
||||||
import environment from '@/api/environment'
|
import environment from '@/api/environment'
|
||||||
|
@ -130,14 +130,28 @@ const columns: Column[] = [{
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
const curd = ref()
|
||||||
|
function load_from_settings() {
|
||||||
|
environment.load_from_settings().then(() => {
|
||||||
|
curd.value.get_list()
|
||||||
|
message.success($gettext('Load successfully'))
|
||||||
|
}).catch(e => {
|
||||||
|
message.error(`${$gettext('Server error')} ${e?.message}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<StdCurd
|
<StdCurd
|
||||||
|
ref="curd"
|
||||||
:title="$gettext('Environment')"
|
:title="$gettext('Environment')"
|
||||||
:api="environment"
|
:api="environment"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
/>
|
>
|
||||||
|
<template #extra>
|
||||||
|
<a @click="load_from_settings">{{ $gettext('Load from settings') }}</a>
|
||||||
|
</template>
|
||||||
|
</StdCurd>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -5,8 +5,6 @@ const route = useRoute()
|
||||||
const info = computed(() => {
|
const info = computed(() => {
|
||||||
if (typeof route.meta.error === 'function')
|
if (typeof route.meta.error === 'function')
|
||||||
return route.meta.error()
|
return route.meta.error()
|
||||||
else if (typeof route.meta.error === 'string')
|
|
||||||
return route.meta.error
|
|
||||||
else
|
else
|
||||||
return $gettext('File Not Found')
|
return $gettext('File Not Found')
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package kernal
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||||
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerPredefinedClusterNodes() {
|
func RegisterPredefinedNodes() {
|
||||||
if len(settings.ClusterSettings.Node) == 0 {
|
if len(settings.ClusterSettings.Node) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package kernal
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/settings"
|
"github.com/0xJacky/Nginx-UI/settings"
|
|
@ -3,6 +3,7 @@ package kernal
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/cert"
|
"github.com/0xJacky/Nginx-UI/internal/cert"
|
||||||
|
"github.com/0xJacky/Nginx-UI/internal/cluster"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/logrotate"
|
"github.com/0xJacky/Nginx-UI/internal/logrotate"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/validation"
|
"github.com/0xJacky/Nginx-UI/internal/validation"
|
||||||
|
@ -44,7 +45,7 @@ func InitAfterDatabase() {
|
||||||
registerPredefinedUser,
|
registerPredefinedUser,
|
||||||
cert.InitRegister,
|
cert.InitRegister,
|
||||||
InitCronJobs,
|
InitCronJobs,
|
||||||
registerPredefinedClusterNodes,
|
cluster.RegisterPredefinedNodes,
|
||||||
analytic.RetrieveNodesStatus,
|
analytic.RetrieveNodesStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,3 +7,13 @@ type Cluster struct {
|
||||||
var ClusterSettings = Cluster{
|
var ClusterSettings = Cluster{
|
||||||
Node: []string{},
|
Node: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReloadCluster() (err error) {
|
||||||
|
err = load()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapTo("cluster", &ClusterSettings)
|
||||||
|
}
|
||||||
|
|
|
@ -39,13 +39,18 @@ func Init(confPath string) {
|
||||||
Setup()
|
Setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setup() {
|
func load() (err error) {
|
||||||
var err error
|
|
||||||
Conf, err = ini.LoadSources(ini.LoadOptions{
|
Conf, err = ini.LoadSources(ini.LoadOptions{
|
||||||
Loose: true,
|
Loose: true,
|
||||||
AllowShadows: true,
|
AllowShadows: true,
|
||||||
}, ConfPath)
|
}, ConfPath)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup() {
|
||||||
|
err := load()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("settings.Setup: %v\n", err)
|
log.Fatalf("settings.Setup: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +77,11 @@ func Setup() {
|
||||||
|
|
||||||
func MapTo() {
|
func MapTo() {
|
||||||
for k, v := range sections {
|
for k, v := range sections {
|
||||||
mapTo(k, v)
|
err := mapTo(k, v)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cfg.MapTo %s err: %v", k, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +110,8 @@ func ProtectedFill(targetSettings interface{}, newSettings interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapTo(section string, v interface{}) {
|
func mapTo(section string, v interface{}) error {
|
||||||
err := Conf.Section(section).MapTo(v)
|
return Conf.Section(section).MapTo(v)
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func reflectFrom(section string, v interface{}) {
|
func reflectFrom(section string, v interface{}) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue