Compare commits

...
23 Commits
Author SHA1 Message Date
nap0oandSuperHsiao 99111a3115 improve server-status theme (#310)
* Add files via upload

* Add files via upload

* Add files via upload

* improve theme-server-status

1.前台分组展示agent
2.一些小优化

---------

Co-authored-by: SuperHsiao <[email protected]>
2023-12-07 21:58:42 +08:00
github-actions[bot] 30652c3d79 update contributors[no ci] 2023-12-07 13:41:51 +00:00
Mmx ac0103a1ee Improve: use alpine as dockerfile base image (#309)
* build: use alpine as base image

* build: use alpine edge instead of latest
2023-12-07 21:41:26 +08:00
github-actions[bot] f59b31590e update contributors[no ci] 2023-12-06 14:42:42 +00:00
Applexad 1bcddf1944 installer: fix docker compose command determination (#307) 2023-12-06 22:42:22 +08:00
卖女孩的小火柴 d790ca04d6 Fix select_version (#306) 2023-12-06 21:35:24 +08:00
github-actions[bot] 2106ca41e1 update contributors[no ci] 2023-12-06 01:35:54 +00:00
Mmx 927bf13ce4 fix: field name "VerifySSL" to "SkipVerifySSL" in Transport config (#305) 2023-12-06 09:35:38 +08:00
github-actions[bot] 859e263815 update contributors[no ci] 2023-12-05 15:23:19 +00:00
Mmx 1dcd899591 Fix Coroutine Leaks and Proxy Handling in http.Client (#304)
* fix: builtin variable conflict

* feat: add pkg/utils/http HttpClientSkipTlsVerify HttpClient

* fix: realtime create http Transport

* fix: http keepalive connection may not reusable

* feat: allow http request use proxy from environment
2023-12-05 23:22:25 +08:00
naiba 3059bf2d49 Update installer version to v0.15.2 2023-12-04 10:23:56 +08:00
naiba 74255717ef Update destination repository URL in sync workflow 2023-12-04 10:21:13 +08:00
github-actions[bot] 8fa59a4639 update contributors[no ci] 2023-11-30 05:16:55 +00:00
Applexad b3e38e8924 Exit after installing agent (#303)
If entered with install_agent argument, variable IS_DOCKER_NEZHA will not be set, thus leading select menu to appear, which could be annoying.
2023-11-30 13:16:39 +08:00
github-actions[bot] 2280e0267c update contributors[no ci] 2023-11-30 02:49:24 +00:00
Applexad 1871c481e4 Fix various bugs in fresh installation (#302) 2023-11-30 10:49:06 +08:00
naiba c3d1eec6bf Update GitHub Actions workflow to include specific paths 2023-11-30 09:52:24 +08:00
github-actions[bot] 6fc8ec9446 update contributors[no ci] 2023-11-30 01:39:22 +00:00
Applexad 52703f38cd Add standalone installation method & OpenRC support for nezha-agent (#300)
* Add standalone installation method & OpenRC support for nezha-agent

* Add missing translations & more precise query

* bump installer version
2023-11-30 09:39:00 +08:00
卖女孩的小火柴 d0707b9b05 Fix: get.daocloud.io 503 (#301) 2023-11-30 09:31:39 +08:00
naiba ad99a5d032 Export custom static folder 2023-11-29 17:13:45 +08:00
naiba a823da1f29 📦 static link 2023-11-29 15:45:32 +08:00
naiba b0b7e9da61 Update badges in README 2023-11-29 09:44:47 +08:00
25 changed files with 1460 additions and 453 deletions
+2 -2
View File
@@ -30,12 +30,12 @@ jobs:
v: true v: true
x: false x: false
race: false race: false
ldflags: -s -w -X github.com/naiba/nezha/service/singleton.Version=${{ steps.extract_branch.outputs.tag }} ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=${{ steps.extract_branch.outputs.tag }}
buildmode: default buildmode: default
- name: fix dist - name: fix dist
run: | run: |
cp dist/dashboard-linux-arm-7 dist/dashboard-linux-arm mv dist/dashboard-linux-arm-7 dist/dashboard-linux-arm
- name: Log in to the GHCR - name: Log in to the GHCR
uses: docker/login-action@master uses: docker/login-action@master
+1 -1
View File
@@ -11,6 +11,6 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: adambirds/[email protected] - uses: adambirds/[email protected]
with: with:
destination_repository: git@jihulab.com:nezha/dashboard.git destination_repository: git@gitee.com:naibahq/nezha.git
destination_branch_name: master destination_branch_name: master
destination_ssh_key: ${{ secrets.GITLAB_SSH_KEY }} destination_ssh_key: ${{ secrets.GITLAB_SSH_KEY }}
+15 -3
View File
@@ -17,10 +17,22 @@ jobs:
- name: Unit test - name: Unit test
run: | run: |
go test -v ./... go test -v ./...
- name: Build test
run: |
go build cmd/dashboard/main.go
- name: Run Gosec Security Scanner - name: Run Gosec Security Scanner
uses: securego/gosec@master uses: securego/gosec@master
with: with:
args: --exclude=G104,G402 ./... args: --exclude=G104,G402 ./...
- name: xgo build
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.21
dest: dist
pkg: cmd/dashboard
prefix: dashboard
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64 # linux/386,
v: true
x: false
race: false
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
buildmode: default
+20 -11
View File
@@ -4,14 +4,12 @@ on:
push: push:
branches: branches:
- master - master
paths-ignore: paths:
- ".github/workflows/codeql-analysis.yml" - "**.go"
- ".github/workflows/test-on-pr.yml" - "go.mod"
- ".github/workflows/contributors.yml" - "go.sum"
- ".github/workflows/sync.yml" - "resource/**"
- ".github/workflows/release.yml" - ".github/workflows/test.yml"
- "README.md"
- ".goreleaser.yml"
jobs: jobs:
tests: tests:
@@ -26,10 +24,21 @@ jobs:
- name: Unit test - name: Unit test
run: | run: |
go test -v ./... go test -v ./...
- name: Build test
run: |
go build cmd/dashboard/main.go
- name: Run Gosec Security Scanner - name: Run Gosec Security Scanner
uses: securego/gosec@master uses: securego/gosec@master
with: with:
args: --exclude=G104,G402 ./... args: --exclude=G104,G402 ./...
- name: xgo build
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.21
dest: dist
pkg: cmd/dashboard
prefix: dashboard
targets: linux/amd64,linux/arm64,linux/arm-7,linux/s390x,linux/riscv64 # linux/386,
v: true
x: false
race: false
ldflags: -s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=test
buildmode: default
+1 -1
View File
@@ -19,4 +19,4 @@
/cmd/dashboard/main /cmd/dashboard/main
/config.yml /config.yml
/resource/template/theme-custom /resource/template/theme-custom
/resource/static/theme-custom /resource/static/custom
+9 -10
View File
@@ -1,18 +1,17 @@
FROM ubuntu:focal-20221130 FROM alpine:edge
ENV TZ="Asia/Shanghai"
ARG TARGETOS ARG TARGETOS
ARG TARGETARCH ARG TARGETARCH
COPY ./script/entrypoint.sh /entrypoint.sh RUN apk update && \
apk upgrade --no-cache && \
apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo 'Asia/Shanghai' >/etc/timezone && \
rm -rf /var/cache/apk/*
RUN export DEBIAN_FRONTEND="noninteractive" && \ COPY ./script/entrypoint.sh /entrypoint.sh
apt update && apt install -y ca-certificates tzdata && \ RUN chmod +x /entrypoint.sh
update-ca-certificates && \
ln -fs /usr/share/zoneinfo/$TZ /etc/localtime && \
dpkg-reconfigure tzdata && \
chmod +x /entrypoint.sh
WORKDIR /dashboard WORKDIR /dashboard
COPY dist/dashboard-${TARGETOS}-${TARGETARCH} ./app COPY dist/dashboard-${TARGETOS}-${TARGETARCH} ./app
+7 -1
View File
@@ -4,7 +4,7 @@
<br> <br>
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small> <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
<br><br> <br><br>
<img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/naiba/nezha?style=for-the-badge&logo=github&label=Dashboard">&nbsp;<img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.15.0-brightgreen?style=for-the-badge&logo=linux"> <img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&style=for-the-badge&logo=github&label=Dashboard">&nbsp;<img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github">&nbsp;<img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?label=Agent%20CI&logo=github&style=for-the-badge">&nbsp;<img src="https://img.shields.io/badge/Installer-v0.15.3-brightgreen?style=for-the-badge&logo=linux">
<br> <br>
<br> <br>
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p> <p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
@@ -71,12 +71,18 @@ You can change the dashboard language in the settings page (`/setting`) after th
<a href="https://github.com/liuyanxi975" title="刘颜溪"> <a href="https://github.com/liuyanxi975" title="刘颜溪">
<img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/> <img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/>
</a> </a>
<a href="https://github.com/applexad" title="Applexad">
<img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="Applexad"/>
</a>
<a href="https://github.com/hhhkkk520" title="Kris"> <a href="https://github.com/hhhkkk520" title="Kris">
<img src="https://avatars.githubusercontent.com/u/52115472?v=4" width="50;" alt="Kris"/> <img src="https://avatars.githubusercontent.com/u/52115472?v=4" width="50;" alt="Kris"/>
</a> </a>
<a href="https://github.com/spiritLHLS" title="spiritlhl"> <a href="https://github.com/spiritLHLS" title="spiritlhl">
<img src="https://avatars.githubusercontent.com/u/103393591?v=4" width="50;" alt="spiritlhl"/> <img src="https://avatars.githubusercontent.com/u/103393591?v=4" width="50;" alt="spiritlhl"/>
</a> </a>
<a href="https://github.com/Mmx233" title="Mmx">
<img src="https://avatars.githubusercontent.com/u/36563672?v=4" width="50;" alt="Mmx"/>
</a>
<a href="https://github.com/rootmelo92118" title="rootmelo92118"> <a href="https://github.com/rootmelo92118" title="rootmelo92118">
<img src="https://avatars.githubusercontent.com/u/32770959?v=4" width="50;" alt="rootmelo92118"/> <img src="https://avatars.githubusercontent.com/u/32770959?v=4" width="50;" alt="rootmelo92118"/>
</a> </a>
+1
View File
@@ -43,6 +43,7 @@ func ServeWeb(port uint) *http.Server {
panic(err) panic(err)
} }
r.StaticFS("/static", http.FS(staticFs)) r.StaticFS("/static", http.FS(staticFs))
r.Static("/static-custom", "resource/static/custom")
routers(r) routers(r)
page404 := func(c *gin.Context) { page404 := func(c *gin.Context) {
+6 -6
View File
@@ -85,13 +85,13 @@ func (r *AlertRule) Snapshot(cycleTransferStats *CycleTransferStats, server *Ser
// Check 传入包含当前报警规则下所有type检查结果的空接口 返回报警持续时间与是否通过报警检查(通过则返回true) // Check 传入包含当前报警规则下所有type检查结果的空接口 返回报警持续时间与是否通过报警检查(通过则返回true)
func (r *AlertRule) Check(points [][]interface{}) (int, bool) { func (r *AlertRule) Check(points [][]interface{}) (int, bool) {
var max int // 报警持续时间 var maxNum int // 报警持续时间
var count int // 检查未通过的个数 var count int // 检查未通过的个数
for i := 0; i < len(r.Rules); i++ { for i := 0; i < len(r.Rules); i++ {
if r.Rules[i].IsTransferDurationRule() { if r.Rules[i].IsTransferDurationRule() {
// 循环区间流量报警 // 循环区间流量报警
if max < 1 { if maxNum < 1 {
max = 1 maxNum = 1
} }
for j := len(points[i]) - 1; j >= 0; j-- { for j := len(points[i]) - 1; j >= 0; j-- {
if points[i][j] != nil { if points[i][j] != nil {
@@ -104,8 +104,8 @@ func (r *AlertRule) Check(points [][]interface{}) (int, bool) {
total := 0.0 total := 0.0
fail := 0.0 fail := 0.0
num := int(r.Rules[i].Duration) num := int(r.Rules[i].Duration)
if num > max { if num > maxNum {
max = num maxNum = num
} }
if len(points) < num { if len(points) < num {
continue continue
@@ -124,5 +124,5 @@ func (r *AlertRule) Check(points [][]interface{}) (int, bool) {
} }
} }
// 仅当所有检查均未通过时 返回false // 仅当所有检查均未通过时 返回false
return max, count != len(r.Rules) return maxNum, count != len(r.Rules)
} }
+8 -10
View File
@@ -1,7 +1,6 @@
package model package model
import ( import (
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@@ -111,17 +110,14 @@ func (n *Notification) setRequestHeader(req *http.Request) error {
} }
func (ns *NotificationServerBundle) Send(message string) error { func (ns *NotificationServerBundle) Send(message string) error {
var verifySSL bool var client *http.Client
n := ns.Notification n := ns.Notification
if n.VerifySSL != nil && *n.VerifySSL { if n.VerifySSL != nil && *n.VerifySSL {
verifySSL = true client = utils.HttpClient
} else {
client = utils.HttpClientSkipTlsVerify
} }
transCfg := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: verifySSL},
}
client := &http.Client{Transport: transCfg, Timeout: time.Minute * 10}
reqBody, err := ns.reqBody(message) reqBody, err := ns.reqBody(message)
if err != nil { if err != nil {
return err return err
@@ -147,13 +143,15 @@ func (ns *NotificationServerBundle) Send(message string) error {
if err != nil { if err != nil {
return err return err
} }
if resp.StatusCode < 200 || resp.StatusCode > 299 {
defer func() { defer func() {
_ = resp.Body.Close() _ = resp.Body.Close()
}() }()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := io.ReadAll(resp.Body) body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("%d@%s %s", resp.StatusCode, resp.Status, string(body)) return fmt.Errorf("%d@%s %s", resp.StatusCode, resp.Status, string(body))
} else {
_, _ = io.Copy(io.Discard, resp.Body)
} }
return nil return nil
+47
View File
@@ -0,0 +1,47 @@
package utils
import (
"crypto/tls"
"net/http"
"time"
)
var (
HttpClientSkipTlsVerify *http.Client
HttpClient *http.Client
)
func init() {
HttpClientSkipTlsVerify = httpClient(_httpClient{
Transport: httpTransport(_httpTransport{
SkipVerifySSL: true,
}),
})
HttpClient = httpClient(_httpClient{
Transport: httpTransport(_httpTransport{
SkipVerifySSL: false,
}),
})
}
type _httpTransport struct {
SkipVerifySSL bool
}
func httpTransport(conf _httpTransport) *http.Transport {
return &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: conf.SkipVerifySSL},
Proxy: http.ProxyFromEnvironment,
}
}
type _httpClient struct {
Transport *http.Transport
}
func httpClient(conf _httpClient) *http.Client {
return &http.Client{
Transport: conf.Transport,
Timeout: time.Minute * 10,
}
}
File diff suppressed because one or more lines are too long
+25
View File
@@ -27,6 +27,10 @@ body[theme="light"] .table {
background: #ffffff; background: #ffffff;
} }
body[theme="light"] .table>thead>tr>th.node-group-tag {
background-color:#ffffff;
}
body[theme="light"] .table-striped tbody > tr.even > td, body[theme="light"] .table-striped tbody > tr.even > td,
body[theme="light"] .table-striped tbody > tr.even > th { body[theme="light"] .table-striped tbody > tr.even > th {
background-color: #F9F9F9; background-color: #F9F9F9;
@@ -37,10 +41,25 @@ body[theme="light"] .table-striped tbody > tr.odd > th {
background-color: #FFF; background-color: #FFF;
} }
body[theme="light"] .table>tbody>tr>td,
body[theme="light"] .table>tbody>tr>th,
body[theme="light"] .table>tfoot>tr>td,
body[theme="light"] .table>tfoot>tr>th,
body[theme="light"] .table>thead>tr>td,
body[theme="light"] .table>thead>tr>th {
line-height:20px;
}
body[theme="light"] .progress-bar { body[theme="light"] .progress-bar {
color: #000; color: #000;
} }
body[theme="light"] .progress-offline .progress-bar-success {
background-image: linear-gradient(grey 0px, grey 100%);
}
}
body[theme="light"] .table-hover > tbody > tr:hover > td { body[theme="light"] .table-hover > tbody > tr:hover > td {
background: #E6E6E6; background: #E6E6E6;
} }
@@ -76,3 +95,9 @@ body[theme="light"] .service-status .warning {
body[theme="light"] .service-day-status-icon { body[theme="light"] .service-day-status-icon {
background-color: #ebebeb; background-color: #ebebeb;
} }
body[theme="light"] footer p a,
body[theme="light"] footer p a:hover {
color: #333333;
text-decoration: none;
}
+47 -81
View File
@@ -8,14 +8,27 @@ body {
min-height: 40px !important; min-height: 40px !important;
} }
.navbar-inner{
margin:0 auto;
}
.pl-md-unset {
max-width: 95vw;
}
.navbar-collapse:not([aria-expanded]) .navbar-nav .dropdown-toggle { .navbar-collapse:not([aria-expanded]) .navbar-nav .dropdown-toggle {
margin-top: 18px; margin-top: 18px;
padding: 0 !important; padding: 0 !important;
} }
.navbar-toggle {
margin-right:0
}
.navbar-brand { .navbar-brand {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
padding:12px 0 0 0;
} }
.node-cell-expand { .node-cell-expand {
@@ -32,18 +45,17 @@ body {
padding-top: 10px; padding-top: 10px;
} }
.dropdown {
margin-right: 10px;
}
.navbar-inverse, .nav.navbar-nav { .navbar-inverse, .nav.navbar-nav {
background-image: linear-gradient(rgb(60, 60, 60) 0px, rgb(34, 34, 34) 100%) !important; background-image: linear-gradient(rgb(60, 60, 60) 0px, rgb(34, 34, 34) 100%) !important;
} }
.navbar-inverse .navbar-nav>li>a {
color:#f1f1f1;
}
.navbar-inverse .navbar-brand { .navbar-inverse .navbar-brand {
font-size: 20px; font-size: 20px;
} }
/* 导航部分 结束 */ /* 导航部分 结束 */
/* 正文部分 开始 */ /* 正文部分 开始 */
@@ -63,6 +75,15 @@ body {
text-align: left; text-align: left;
} }
.table>thead>tr>th{
border:none;
}
.table .node-group-tag {
font-size: 18px;
padding-bottom:15px;
}
.progress { .progress {
margin-bottom: 0; margin-bottom: 0;
} }
@@ -78,6 +99,10 @@ body {
border-top: 0 !important; border-top: 0 !important;
} }
.accordian-body{
margin: 10px 0px 10px 18px;
}
.node-cell.center { .node-cell.center {
text-align: center !important; text-align: center !important;
} }
@@ -147,104 +172,45 @@ body {
} }
/* 服务页 正文结束 */ /* 服务页 正文结束 */
@media only screen and (max-width: 1200px) { @media only screen and (max-width: 1200px) {
.node-cell.os, .accordian-body{
.node-cell.location, margin: 5px 0px 5px 10px;
.node-cell.uptime { }
display: none; .table .node-group-tag {
visibility: hidden; font-size:16px;
padding-bottom:6px;
} }
} }
@media only screen and (max-width: 720px) { @media only screen and (max-width: 720px) {
body { body {
font-size: 10px !important; font-size: 10px !important;
padding-top:60px !important;
} }
.content { .content {
padding: 0; padding: 0;
margin-bottom: 10px;
} }
.node-cell.os, .node-cell.os,
.node-cell.location,
.node-cell.uptime {
display: none;
visibility: hidden;
}
.service-day-status-icon {
width: 8px;
height: 8px;
margin-right: 2px;
border-radius: 3px;
}
}
@media only screen and (max-width: 620px) {
body {
font-size: 10px !important;
}
.content {
padding: 0;
}
.node-cell.type,
.node-cell.location,
.node-cell.uptime, .node-cell.uptime,
.node-cell.traffic{ .node-cell.traffic{
display: none; display: none;
visibility: hidden; visibility: hidden;
} }
.node-cell.location{
.service-day-status-icon { display: table-cell;
visibility: visible;
} }
} .node-cell-os-text,.node-cell-location-text{
@media only screen and (max-width: 533px) {
body {
font-size: 10px !important;
}
.content {
padding: 0;
}
.node-cell.os,
.node-cell.location,
.node-cell.uptime,
.node-cell.traffic {
display: none; display: none;
visibility: hidden; visibility: hidden;
} }
.accordian-body{
.service-day-status-icon { margin: 5px 0px 5px 10px;
} }
} .table .node-group-tag {
font-size:12px;
@media only screen and (max-width: 450px) { padding-bottom:6px;
body {
font-size: 10px !important;
}
.content {
padding: 0;
}
.node-cell.type,
.node-cell.location,
.node-cell.uptime,
.node-cell.traffic {
display: none;
visibility: hidden;
}
.node-cell.cpu,
.node-cell.ram,
.node-cell.hdd {
min-width: 25px;
max-width: 50px;
} }
} }
+1 -2
View File
@@ -1,8 +1,7 @@
{{define "theme-server-status/content-footer"}} {{define "theme-server-status/content-footer"}}
<footer class="container" style="padding-bottom: 2rem;"> <footer class="container" style="padding-bottom: 2rem;">
<p style="text-align: center; font-size: 10px;"> <p style="text-align: center; font-size: 10px;">
{{ .Conf.Site.Brand }} | Theme <a href="https://github.com/cppla/ServerStatus">ServerStatus</a> | Powered by <a {{ .Conf.Site.Brand }} | Theme <a target="_blank" href="https://github.com/cppla/ServerStatus">ServerStatus</a> | Powered by <a target="_blank" href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> {{.Version}}
href="https://github.com/naiba/nezha">{{tr "NezhaMonitoring"}}</a> {{.Version}}
</p> </p>
</footer> </footer>
{{end}} {{end}}
+5 -6
View File
@@ -1,7 +1,6 @@
{{define "theme-server-status/header"}} {{define "theme-server-status/header"}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{.Conf.Language}}"> <html lang="{{.Conf.Language}}">
<head> <head>
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<meta charset="utf-8"> <meta charset="utf-8">
@@ -9,11 +8,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/theme-server-status/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/theme-server-status/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/theme-server-status/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="/static/theme-server-status/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20231109"> <link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20231207">
<link rel="stylesheet" href="/static/theme-server-status/css/dark.css"> <link rel="stylesheet" href="/static/theme-server-status/css/dark.css">
<link rel="stylesheet" href="/static/theme-server-status/css/light.css"> <link rel="stylesheet" href="/static/theme-server-status/css/light.css">
<link href="https://cdn.staticfile.org/font-logos/0.17/font-logos.min.css" type="text/css" rel="stylesheet" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.staticfile.org/semantic-ui/2.4.1/semantic.min.css"> <link rel="stylesheet" href="https://cdn.staticfile.org/font-logos/0.17/font-logos.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/semantic-ui/2.4.1/semantic.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/[email protected]/css/flag-icons.min.css">
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" /> <link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -23,12 +24,10 @@
{{if ts .CustomCode}} {{if ts .CustomCode}}
{{.CustomCode|safe}} {{.CustomCode|safe}}
{{end}} {{end}}
<script src="/static/theme-server-status/js/jquery.min.js"></script> <script src="/static/theme-server-status/js/jquery.min.js"></script>
<script src="/static/theme-server-status/js/bootstrap.min.js"></script> <script src="/static/theme-server-status/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script> <script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script src="/static/theme-server-status/js/mixin.js"></script> <script src="/static/theme-server-status/js/mixin.js"></script>
</head> </head>
<body> <body>
{{end}} {{end}}
+79 -60
View File
@@ -2,26 +2,30 @@
{{template "theme-server-status/header" .}} {{template "theme-server-status/header" .}}
<div id="app"> <div id="app">
{{template "theme-server-status/content-nav" .}} {{template "theme-server-status/content-nav" .}}
<div class="container table-responsive content" style="max-width: 95vw"> <div class="container table-responsive content" style="max-width: 95vw" v-for="group in nodes">
<table class="table table-striped table-condensed table-hover"> <table class="table table-striped table-condensed table-hover">
<thead> <thead>
<tr> <tr>
<th class="node-cell status center">🍀 {{tr "Status"}}</th> <th class="node-group-tag" colspan="16" style="border:none;">@#(group.Tag!==''?group.Tag:'{{tr "Default"}}')#@</th>
<th class="node-cell name">🚀 {{tr "Name"}}</th> </th>
<th class="node-cell os">🗂 {{tr "Platform"}}</th> </tr>
<th class="node-cell location center">🌍 {{tr "Location"}}</th> <tr>
<th class="node-cell uptime center">⏱️ {{tr "Uptime"}}</th> <th class="node-cell status center">{{tr "Status"}}</th>
<th class="node-cell load center">📋{{tr "Load"}}</th> <th class="node-cell name center">{{tr "Name"}}</th>
<th class="node-cell network center">🚦 {{tr "NetSpeed"}}↓|↑</th> <th class="node-cell os center">{{tr "Platform"}}</th>
<th class="node-cell traffic center">📊 {{tr "NetTransfer"}}↓|↑</th> <th class="node-cell location center">{{tr "Location"}}</th>
<th class="node-cell cpu center">🎯 {{tr "CpuUsed"}}</th> <th class="node-cell uptime center">{{tr "Uptime"}}</th>
<th class="node-cell ram center">⚡ {{tr "MemUsed"}}</th> <th class="node-cell load center">{{tr "Load"}}</th>
<th class="node-cell hdd center">💾 {{tr "DiskUsed"}}</th> <th class="node-cell network center">{{tr "NetSpeed"}}↓|↑</th>
<th class="node-cell traffic center">{{tr "NetTransfer"}}↓|↑</th>
<th class="node-cell cpu center">{{tr "CpuUsed"}}</th>
<th class="node-cell ram center">{{tr "MemUsed"}}</th>
<th class="node-cell hdd center">{{tr "DiskUsed"}}</th>
</tr> </tr>
</thead> </thead>
<tbody id="servers"> <tbody id="servers">
<template v-for="(node,index) in nodes"> <template v-for="(node,index) in group.data">
<tr :id="'r'+index" data-toggle="collapse" :data-target="'#rt'+index" class="accordion-toggle" <tr :id="'r'+node.ID" data-toggle="collapse" :data-target="'#rt'+node.ID" class="accordion-toggle"
:class="index % 2 === 0 ? 'odd': 'even'"> :class="index % 2 === 0 ? 'odd': 'even'">
<td class="node-cell status center"> <td class="node-cell status center">
<div class="status-container"> <div class="status-container">
@@ -29,36 +33,36 @@
<div v-else class="status-icon offline"></div> <div v-else class="status-icon offline"></div>
</div> </div>
</td> </td>
<td class="node-cell name">@#node.name#@</td> <td class="node-cell name center">@#node.name#@</td>
<td class="node-cell os"> <td class="node-cell os center">
<i v-if='node.os == "darwin"' class="apple icon"></i> <i v-if='node.os == "darwin"' class="apple icon"></i>
<i v-else-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i> <i v-else-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
<i v-else :class="'fl-' + getFontLogoClass(node.host.Platform)"></i> <i v-else :class="'fl-' + getFontLogoClass(node.host.Platform)"></i>
@#node.os#@ <span class="node-cell-os-text">@#node.os#@</span>
</td> </td>
<td style="text-align: center;" class="node-cell location"> <td style="text-align: center;" class="node-cell location">
<i :class="node.location + ' flag'"></i>&nbsp; <i :class="'fi fi-' + node.location"></i>
<span class="text-uppercase">@#node.location#@</span> <span class="node-cell-location-text text-uppercase">&nbsp;@#node.location#@</span>
</td> </td>
<td style="text-align: center;" class="node-cell uptime">@#node.uptime#@</td> <td style="text-align: center;" class="node-cell uptime">@#node.uptime#@</td>
<td style="text-align: center;" class="node-cell load">@#node.load#@</td> <td style="text-align: center;" class="node-cell load">@#node.load#@</td>
<td style="text-align: center;" class="node-cell network">@#node.network#@</td> <td style="text-align: center;" class="node-cell network">@#node.network#@</td>
<td style="text-align: center;" class="node-cell traffic">@#node.traffic#@</td> <td style="text-align: center;" class="node-cell traffic">@#node.traffic#@</td>
<td class="node-cell cpu"> <td class="node-cell cpu">
<div class="progress"> <div :class="['progress', node.online ? 'progress-online' : 'progress-offline']">
<div :style="node.cpu.style" :class="node.cpu.class"><small>@#node.cpu.percent#@%</small> <div :style="node.cpu.style" :class="node.cpu.class"><small>@#node.cpu.percent#@%</small>
</div> </div>
</div> </div>
</td> </td>
<td class="node-cell memory"> <td class="node-cell memory">
<div class="progress"> <div :class="['progress', node.online ? 'progress-online' : 'progress-offline']">
<div :style="node.memory.style" :class="node.memory.class"> <div :style="node.memory.style" :class="node.memory.class">
<small>@#node.memory.percent#@%</small> <small>@#node.memory.percent#@%</small>
</div> </div>
</div> </div>
</td> </td>
<td class="node-cell hdd"> <td class="node-cell hdd">
<div class="progress"> <div :class="['progress', node.online ? 'progress-online' : 'progress-offline']">
<div :style="node.hdd.style" :class="node.hdd.class"><small>@#node.hdd.percent#@%</small> <div :style="node.hdd.style" :class="node.hdd.class"><small>@#node.hdd.percent#@%</small>
</div> </div>
</div> </div>
@@ -66,24 +70,16 @@
</tr> </tr>
<tr class="expandRow" :class="index % 2 === 0 ? 'odd': 'even'"> <tr class="expandRow" :class="index % 2 === 0 ? 'odd': 'even'">
<td colspan="16"> <td colspan="16">
<div class="accordian-body collapse" :id="'rt'+index"> <div class="accordian-body collapse" :id="'rt'+node.ID">
<div style="display: flex;align-items: center;justify-content: center;flex-direction: column;"> <div style="display: flex;left-items: center;justify-content: center;flex-direction: column; max-width: 89vw">
<div style="display: flex;align-items: flex-start;justify-content: center;flex-direction: column; width: 450px;max-width: 90vw">
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Platform"}}:</span> <span class="node-cell-expand-label">{{tr "Platform"}}:</span>
@#node.host.Platform#@ @#node.host.Platform#@-@#node.host.PlatformVersion#@
</span> [<span v-if="node.host.Virtualization">@#node.host.Virtualization#@:</span>@#node.host.Arch#@]
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Location"}}:</span>
<i :class="node.location + ' flag'"></i>
</span> </span>
<span class="node-cell-expand" v-if="node.host.CPU"> <span class="node-cell-expand" v-if="node.host.CPU">
<span class="node-cell-expand-label">CPU:</span> <span class="node-cell-expand-label">CPU:</span>
@#node.host.CPU.join(",")#@ @#node.host.CPU.join(",")#@
</span>
<span class="node-cell-expand load">
<span class="node-cell-expand-label">{{tr "Load"}}:</span>
@#toFixed2(node.state.Load1)#@ / @#toFixed2(node.state.Load5)#@ /@#toFixed2(node.state.Load15)#@
</span> </span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span> <span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
@@ -93,6 +89,11 @@
<span class="node-cell-expand-label">{{tr "MemUsed"}}:</span> <span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
@#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@(@#toFixed2(node.state.MemUsed / node.host.MemTotal * 100)#@%) @#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@(@#toFixed2(node.state.MemUsed / node.host.MemTotal * 100)#@%)
</span> </span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
<span v-if="node.host.SwapTotal">(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
</span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span> <span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
<i class="arrow alternate circle down outline icon" <i class="arrow alternate circle down outline icon"
@@ -100,22 +101,9 @@
<i class="arrow alternate circle up outline icon" <i class="arrow alternate circle up outline icon"
style="margin: 0"></i>@#formatByteSize(node.state.NetOutTransfer)#@ style="margin: 0"></i>@#formatByteSize(node.state.NetOutTransfer)#@
</span> </span>
<span class="node-cell-expand"> <span class="node-cell-expand load">
<span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span> <span class="node-cell-expand-label">{{tr "Load"}}:</span>
@#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@ @#toFixed2(node.state.Load1)#@ / @#toFixed2(node.state.Load5)#@ / @#toFixed2(node.state.Load15)#@
<span v-if="node.host.SwapTotal">(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "BootTime"}}:</span>
@#formatTimestamp(node.host.BootTime)#@
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "LastActive"}}:</span>
@#new Date(node.lastActive).toLocaleString()#@
</span>
<span class="node-cell-expand" v-if="node.host.Virtualization">
<span class="node-cell-expand-label">{{tr "Virtualization"}}:</span>
@#node.host.Virtualization#@
</span> </span>
<span class="node-cell-expand"> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "ProcessCount"}}:</span> <span class="node-cell-expand-label">{{tr "ProcessCount"}}:</span>
@@ -125,19 +113,29 @@
<span class="node-cell-expand-label">{{tr "ConnCount"}}:</span> <span class="node-cell-expand-label">{{tr "ConnCount"}}:</span>
TCP @#node.state.TcpConnCount#@ / UDP @#node.state.UdpConnCount#@ TCP @#node.state.TcpConnCount#@ / UDP @#node.state.UdpConnCount#@
</span> </span>
</div> <span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "BootTime"}}:</span>
@#formatTimestamp(node.host.BootTime)#@
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "LastActive"}}:</span>
@#new Date(node.lastActive).toLocaleString()#@
</span>
<span class="node-cell-expand">
<span class="node-cell-expand-label">{{tr "Version"}}:</span>
@#node.host.Version#@
</span>
</div> </div>
</div> </div>
</td> </td>
</tr> </tr>
</template> </template>
</tbody> </tbody>
</table> </table>
<br/>
</div> </div>
{{template "theme-server-status/content-footer" .}} {{template "theme-server-status/content-footer" .}}
</div> </div>
<script> <script>
new Vue({ new Vue({
el: '#app', el: '#app',
@@ -148,7 +146,7 @@
mixins: [mixinsVue], mixins: [mixinsVue],
created() { created() {
const initData = JSON.parse('{{.Servers}}').servers; const initData = JSON.parse('{{.Servers}}').servers;
this.nodes = this.handleNodes(initData); this.nodes = groupingData(this.handleNodes(initData),"Tag");
this.initTheme() this.initTheme()
}, },
mounted() { mounted() {
@@ -233,17 +231,17 @@
return x !== "NaN undefined" ? x : '0B' return x !== "NaN undefined" ? x : '0B'
}, },
formatPercent(live, used, total) { formatPercent(live, used, total) {
const percent = live ? (this.toFixed2(used / total * 100) || 0) : 1 const percent = live ? (this.toFixed2(used / total * 100) || 0) : 0
return this.formatPercents(percent) return this.formatPercents(percent)
}, },
formatPercents(percent) { formatPercents(percent) {
if (percent <= 0) { if (percent <= 0) {
percent = 1; percent = 0;
} }
if (!this.cache[percent]) { if (!this.cache[percent]) {
this.cache[percent] = { this.cache[percent] = {
class: 'progress-bar progress-bar-success', class: 'progress-bar progress-bar-success',
style: `width: ${parseInt(percent)}%`, style: `width: ${parseInt(percent)+1}%`,
percent, percent,
} }
if (percent < 80) { if (percent < 80) {
@@ -282,7 +280,7 @@
data.servers[i].live = data.now - lastActive <= 10 * 1000; data.servers[i].live = data.now - lastActive <= 10 * 1000;
} }
} }
this.nodes = this.handleNodes(data.servers) this.nodes = groupingData(this.handleNodes(data.servers),"Tag");
} }
ws.onclose = () => { ws.onclose = () => {
setTimeout(function () { setTimeout(function () {
@@ -296,13 +294,14 @@
handleNodes(servers) { handleNodes(servers) {
let nodes = [] let nodes = []
servers?.forEach(server => { servers?.forEach(server => {
let platform = server.Host.Platform let platform = server.Host.Platform;
if (this.isWindowsPlatform(server.Host.Platform)) { if (this.isWindowsPlatform(platform)) {
platform = "windows" platform = "windows"
}else if (platform === "immortalwrt") { }else if (platform === "immortalwrt") {
platform = "openwrt" platform = "openwrt"
} }
let node = { let node = {
ID: server.ID,
name: server.Name, name: server.Name,
os: platform, os: platform,
location: server.Host.CountryCode, location: server.Host.CountryCode,
@@ -317,6 +316,7 @@
state: server.State, state: server.State,
host: server.Host, host: server.Host,
lastActive: server.LastActive, lastActive: server.LastActive,
Tag: server.Tag,
} }
nodes.push(node) nodes.push(node)
}) })
@@ -328,6 +328,25 @@
} }
}) })
function groupingData(data, field) {
let map = new Map();
let dest = [];
data.forEach(item => {
if (!map.has(item[field])) {
dest.push({
[field]: item[field],
data: [item]
});
map.set(item[field], item);
} else {
dest.find(dItem => dItem[field] === item[field]).data.push(item);
}
});
return dest;
}
</script> </script>
{{template "theme-server-status/footer" .}} {{template "theme-server-status/footer" .}}
{{end}} {{end}}
+8 -8
View File
@@ -6,23 +6,23 @@
<table class="table table-striped table-condensed service-status"> <table class="table table-striped table-condensed service-status">
<thead> <thead>
<tr> <tr>
<th class="node-cell" style="min-width: 60px">🍀 {{tr "Status"}}</th> <th class="node-cell center" style="min-width:60px">{{tr "Status"}}</th>
<th class="node-cell" style="min-width: 60px">🚀 {{tr "Name"}}</th> <th class="node-cell center" style="min-width:50px">{{tr "Name"}}</th>
<th class="node-cell center">🗂 {{tr "Details"}}</th> <th class="node-cell center">{{tr "Details"}}</th>
<th class="node-cell center" style="min-width: 80px">⚡️{{tr "AverageLatency"}}</th> <th class="node-cell center" style="min-width:80px">{{tr "AverageLatency"}}</th>
<th class="node-cell center" style="min-width: 80px">⏱️ {{tr "30DaysOnline"}}</th> <th class="node-cell center" style="min-width:80px">{{tr "30DaysOnline"}}</th>
</tr> </tr>
</thead> </thead>
<tbody id="servers"> <tbody id="servers">
<template v-for="service in services"> <template v-for="service in services">
<tr> <tr>
<td style="text-align: left" class="node-cell"> <td class="node-cell center">
<div class="delay-today"> <div class="delay-today">
<i class="delay-today" :class="service.health.className"></i> <i class="delay-today" :class="service.health.className"></i>
@#service.health.text#@ @#service.health.text#@
</div> </div>
</td> </td>
<td class="node-cell">@#service.name#@</td> <td class="node-cell center">@#service.name#@</td>
<td class="node-cell center"> <td class="node-cell center">
<template v-for="(item,index) in service.dayDetail"> <template v-for="(item,index) in service.dayDetail">
<div class="service-day-status-icon" :class="item.className" <div class="service-day-status-icon" :class="item.className"
@@ -44,7 +44,7 @@
</table> </table>
</div> </div>
<div class="container" style="margin-bottom: 20px;padding:unset;max-width: 95vw"> <div class="container" style="padding:unset;max-width: 95vw">
{{if .CycleTransferStats}} {{if .CycleTransferStats}}
<h4 style="text-align: center;">{{tr "CycleTransferStats"}}</h4> <h4 style="text-align: center;">{{tr "CycleTransferStats"}}</h4>
<div class="table-responsive content"> <div class="table-responsive content">
+1 -2
View File
@@ -6,10 +6,9 @@ services:
restart: always restart: always
volumes: volumes:
- ./data:/dashboard/data - ./data:/dashboard/data
- ./static-custom/static:/dashboard/resource/static/custom:ro
- ./theme-custom/template:/dashboard/resource/template/theme-custom:ro - ./theme-custom/template:/dashboard/resource/template/theme-custom:ro
- ./theme-custom/static:/dashboard/resource/static/theme-custom:ro
- ./dashboard-custom/template:/dashboard/resource/template/dashboard-custom:ro - ./dashboard-custom/template:/dashboard/resource/template/dashboard-custom:ro
- ./dashboard-custom/static:/dashboard/resource/static/dashboard-custom:ro
ports: ports:
- nz_site_port:80 - nz_site_port:80
- nz_grpc_port:nz_grpc_port - nz_grpc_port:nz_grpc_port
+428 -13
View File
@@ -11,7 +11,10 @@ NZ_BASE_PATH="/opt/nezha"
NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard" NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent" NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service" NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
NZ_VERSION="v0.15.0" NZ_AGENT_SERVICERC="/etc/init.d/nezha-agent"
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
NZ_VERSION="v0.15.3"
red='\033[0;31m' red='\033[0;31m'
green='\033[0;32m' green='\033[0;32m'
@@ -71,12 +74,14 @@ pre_check() {
Get_Docker_URL="get.docker.com" Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" " Get_Docker_Argu=" "
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard" Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
GITHUB_RELEASE_URL="github.com/naiba/nezha/releases/latest/download"
else else
GITHUB_RAW_URL="jihulab.com/nezha/dashboard/-/raw/master" GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
GITHUB_URL="dn-dao-github-mirror.daocloud.io" GITHUB_URL="dn-dao-github-mirror.daocloud.io"
Get_Docker_URL="get.daocloud.io/docker" Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" -s docker --mirror Aliyun" Get_Docker_Argu=" -s docker --mirror Aliyun"
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard" Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
GITHUB_RELEASE_URL="hub.fgit.cf/naiba/nezha/releases/latest/download"
fi fi
} }
@@ -124,6 +129,7 @@ install_base() {
(command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) || (command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
(install_soft curl wget git unzip) (install_soft curl wget git unzip)
} }
install_arch(){ install_arch(){
echo -e "${green}提示: ${plain} Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次\n" echo -e "${green}提示: ${plain} Arch安装libselinux需添加nezha-agent用户,安装完会自动删除,建议手动检查一次\n"
read -e -r -p "是否安装libselinux? [Y/n] " input read -e -r -p "是否安装libselinux? [Y/n] " input
@@ -162,7 +168,7 @@ install_dashboard() {
echo -e "> 安装面板" echo -e "> 安装面板"
# 哪吒监控文件夹 # 哪吒监控文件夹
if [ ! -d "${NZ_DASHBOARD_PATH}" ]; then if [ ! -d "${NZ_DASHBOARD_PATH}/docker-compose.yaml" ]; then
mkdir -p $NZ_DASHBOARD_PATH mkdir -p $NZ_DASHBOARD_PATH
else else
echo "您可能已经安装过面板端,重复安装会覆盖数据,请注意备份。" echo "您可能已经安装过面板端,重复安装会覆盖数据,请注意备份。"
@@ -204,6 +210,45 @@ install_dashboard() {
fi fi
} }
install_dashboard_standalone() {
install_base
echo -e "> 安装面板"
# 哪吒监控文件夹
if [ ! -d "${NZ_DASHBOARD_PATH}/app" ]; then
mkdir -p $NZ_DASHBOARD_PATH
else
echo "您可能已经安装过面板端,重复安装会覆盖数据,请注意备份。"
read -e -r -p "是否退出安装? [Y/n] " input
case $input in
[yY][eE][sS] | [yY])
echo "退出安装"
exit 0
;;
[nN][oO] | [nN])
echo "继续安装"
;;
*)
echo "退出安装"
exit 0
;;
esac
fi
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
fi
chmod 777 -R $NZ_DASHBOARD_PATH
modify_dashboard_config_standalone 0
if [[ $# == 0 ]]; then
before_show_menu
fi
}
selinux(){ selinux(){
#判断当前的状态 #判断当前的状态
if [ "$os_alpine" != 1 ];then if [ "$os_alpine" != 1 ];then
@@ -275,6 +320,13 @@ modify_agent_config() {
echo -e "${red}文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}" echo -e "${red}文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
return 0 return 0
fi fi
else
wget -t 2 -T 10 -O $NZ_AGENT_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-agent >/dev/null 2>&1
chmod +x $NZ_AGENT_SERVICERC
if [[ $? != 0 ]]; then
echo -e "${red}Fail to download service, please check if the network can link ${GITHUB_RAW_URL}${plain}"
return 0
fi
fi fi
if [ $# -lt 3 ]; then if [ $# -lt 3 ]; then
@@ -308,8 +360,10 @@ modify_agent_config() {
sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICE} sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICE}
[ -n "${args}" ] && sed -i "/ExecStart/ s/$/ ${args}/" ${NZ_AGENT_SERVICE} [ -n "${args}" ] && sed -i "/ExecStart/ s/$/ ${args}/" ${NZ_AGENT_SERVICE}
else else
echo "@reboot ${NZ_AGENT_PATH}/nezha-agent -s ${nz_grpc_host}:${nz_grpc_port} -p ${nz_client_secret} ${args}" >> /etc/crontabs/root sed -i "s/nz_grpc_host/${nz_grpc_host}/" ${NZ_AGENT_SERVICERC}
crond sed -i "s/nz_grpc_port/${nz_grpc_port}/" ${NZ_AGENT_SERVICERC}
sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICERC}
[ -n "${args}" ] && sed -i "/command_args/ s/\"$/ ${args}\"/" ${NZ_AGENT_SERVICERC}
fi fi
echo -e "Agent配置 ${green}修改成功,请稍等重启生效${plain}" echo -e "Agent配置 ${green}修改成功,请稍等重启生效${plain}"
@@ -319,12 +373,13 @@ modify_agent_config() {
systemctl enable nezha-agent systemctl enable nezha-agent
systemctl restart nezha-agent systemctl restart nezha-agent
else else
nohup ${NZ_AGENT_PATH}/nezha-agent -s ${nz_grpc_host}:${nz_grpc_port} -p ${nz_client_secret} ${args} >/dev/null 2>&1 & rc-update add nezha-agent
rc-service nezha-agent restart
fi fi
if [[ $# == 0 ]]; then #if [[ $# == 0 ]]; then
before_show_menu # before_show_menu
fi #fi
} }
modify_dashboard_config() { modify_dashboard_config() {
@@ -393,6 +448,78 @@ modify_dashboard_config() {
fi fi
} }
modify_dashboard_config_standalone() {
echo -e "> 修改面板配置"
echo -e "正在下载配置模板"
wget -t 2 -T 10 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo -e "${red}下载文件失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
return 0
fi
echo "关于 GitHub Oauth2 应用:在 https://github.com/settings/developers 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback" &&
echo "关于 Gitee Oauth2 应用:在 https://gitee.com/oauth/applications 创建,无需审核,Callback 填 http(s)://域名或IP/oauth2/callback" &&
read -ep "请输入 OAuth2 提供商(github/gitlab/jihulab/gitee,默认 github): " nz_oauth2_type &&
read -ep "请输入 Oauth2 应用的 Client ID: " nz_github_oauth_client_id &&
read -ep "请输入 Oauth2 应用的 Client Secret: " nz_github_oauth_client_secret &&
read -ep "请输入 GitHub/Gitee 登录名作为管理员,多个以逗号隔开: " nz_admin_logins &&
read -ep "请输入站点标题: " nz_site_title &&
read -ep "请输入站点访问端口: (默认 8008)" nz_site_port &&
read -ep "请输入用于 Agent 接入的 RPC 端口: (默认 5555)" nz_grpc_port
if [[ -z "${nz_admin_logins}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
echo -e "${red}所有选项都不能为空${plain}"
before_show_menu
return 1
fi
if [[ -z "${nz_site_port}" ]]; then
nz_site_port=8008
fi
if [[ -z "${nz_grpc_port}" ]]; then
nz_grpc_port=5555
fi
if [[ -z "${nz_oauth2_type}" ]]; then
nz_oauth2_type=github
fi
sed -i "s/nz_oauth2_type/${nz_oauth2_type}/" /tmp/nezha-config.yaml
sed -i "s/nz_admin_logins/${nz_admin_logins}/" /tmp/nezha-config.yaml
sed -i "s/nz_grpc_port/${nz_grpc_port}/" /tmp/nezha-config.yaml
sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" /tmp/nezha-config.yaml
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
sed -i "s/nz_language/zh-CN/" /tmp/nezha-config.yaml
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
mkdir -p $NZ_DASHBOARD_PATH/data
mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
echo -e "正在下载服务文件"
if [ "$os_alpine" != 1 ];then
wget -t 2 -T 10 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
else
wget -t 2 -T 10 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
chmod +x $NZ_DASHBOARD_SERVICERC
if [[ $? != 0 ]]; then
echo -e "${red}文件下载失败,请检查本机能否连接 ${GITHUB_RAW_URL}${plain}"
return 0
fi
fi
echo -e "面板配置 ${green}修改成功,请稍等重启生效${plain}"
restart_and_update_standalone
if [[ $# == 0 ]]; then
before_show_menu
fi
}
restart_and_update() { restart_and_update() {
echo -e "> 重启并更新面板" echo -e "> 重启并更新面板"
@@ -421,6 +548,40 @@ restart_and_update() {
fi fi
} }
restart_and_update_standalone() {
echo -e "> 重启并更新面板"
cd $NZ_DASHBOARD_PATH
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
wget -qO app.zip $GITHUB_RELEASE_URL/dashboard-linux-$os_arch.zip >/dev/null 2>&1 && unzip -qq app.zip && mv dist/dashboard-linux-$os_arch app && rm -r app.zip dist
if [ "$os_alpine" != 1 ];then
systemctl daemon-reload
systemctl enable nezha-dashboard
systemctl restart nezha-dashboard
else
rc-update add nezha-dashboard
rc-service nezha-dashboard restart
fi
if [[ $? == 0 ]]; then
echo -e "${green}哪吒监控 重启成功${plain}"
echo -e "默认管理面板地址:${yellow}域名:站点访问端口${plain}"
else
echo -e "${red}重启失败,可能是因为启动时间超过了两秒,请稍后查看日志信息${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
start_dashboard() { start_dashboard() {
echo -e "> 启动面板" echo -e "> 启动面板"
@@ -442,6 +603,26 @@ start_dashboard() {
fi fi
} }
start_dashboard_standalone() {
echo -e "> 启动面板"
if [ "$os_alpine" != 1 ]; then
systemctl start nezha-dashboard
else
rc-service nezha-dashboard start
fi
if [[ $? == 0 ]]; then
echo -e "${green}哪吒监控 启动成功${plain}"
else
echo -e "${red}启动失败,请稍后查看日志信息${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
stop_dashboard() { stop_dashboard() {
echo -e "> 停止面板" echo -e "> 停止面板"
@@ -463,6 +644,26 @@ stop_dashboard() {
fi fi
} }
stop_dashboard_standalone() {
echo -e "> 停止面板"
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
if [[ $? == 0 ]]; then
echo -e "${green}哪吒监控 停止成功${plain}"
else
echo -e "${red}停止失败,请稍后查看日志信息${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
show_dashboard_log() { show_dashboard_log() {
echo -e "> 获取面板日志" echo -e "> 获取面板日志"
@@ -478,6 +679,20 @@ show_dashboard_log() {
fi fi
} }
show_dashboard_log_standalone() {
echo -e "> 获取面板日志"
if [ "$os_alpine" != 1 ]; then
journalctl -xf -u nezha-dashboard.service
else
echo "很抱歉,OpenRC 无此功能"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
uninstall_dashboard() { uninstall_dashboard() {
echo -e "> 卸载管理面板" echo -e "> 卸载管理面板"
@@ -498,10 +713,38 @@ uninstall_dashboard() {
fi fi
} }
uninstall_dashboard_standalone() {
echo -e "> 卸载管理面板"
rm -rf $NZ_DASHBOARD_PATH
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
if [ "$os_alpine" != 1 ]; then
rm $NZ_DASHBOARD_SERVICE
else
rm $NZ_DASHBOARD_SERVICERC
fi
clean_all
if [[ $# == 0 ]]; then
before_show_menu
fi
}
show_agent_log() { show_agent_log() {
echo -e "> 获取Agent日志" echo -e "> 获取Agent日志"
if [ "$os_alpine" != 1 ]; then
journalctl -xf -u nezha-agent.service journalctl -xf -u nezha-agent.service
else
echo "很抱歉,OpenRC 无此功能"
fi
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
@@ -517,8 +760,9 @@ uninstall_agent() {
rm -rf $NZ_AGENT_SERVICE rm -rf $NZ_AGENT_SERVICE
systemctl daemon-reload systemctl daemon-reload
else else
grep -q 'nezha-agent' /var/spool/cron/crontabs/root && sed -i "/nezha-agent/d" /var/spool/cron/crontabs/root rc-update del nezha-agent
pkill nezha-agent rc-service nezha-agent stop
rm -rf $NZ_AGENT_SERVICERC
fi fi
rm -rf $NZ_AGENT_PATH rm -rf $NZ_AGENT_PATH
@@ -532,7 +776,11 @@ uninstall_agent() {
restart_agent() { restart_agent() {
echo -e "> 重启Agent" echo -e "> 重启Agent"
if [ "$os_alpine" != 1 ];then
systemctl restart nezha-agent.service systemctl restart nezha-agent.service
else
rc-service nezha-agent restart
fi
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
@@ -545,6 +793,44 @@ clean_all() {
fi fi
} }
select_version() {
DOCKER_COMPOSE_COMMAND=""
if docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE_COMMAND="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE_COMMAND="docker-compose"
fi
if [[ -n $DOCKER_COMPOSE_COMMAND ]]; then
if $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
IS_DOCKER_NEZHA=1
return
fi
fi
if [[ -f $NZ_DASHBOARD_PATH/app ]]; then
IS_DOCKER_NEZHA=0
else
echo -e "${yellow}请自行选择您的安装方式(如果你是安装Agent,输入哪个都是一样的):\n1. Docker\n2. 独立安装${plain}"
while true; do
read -e -r -p "请输入数字 [1-2]:" option
case "${option}" in
1)
IS_DOCKER_NEZHA=1
break
;;
2)
IS_DOCKER_NEZHA=0
break
;;
*)
echo "输入有误,请重新输入"
;;
esac
done
fi
}
show_usage() { show_usage() {
echo "哪吒监控 管理脚本使用方法: " echo "哪吒监控 管理脚本使用方法: "
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
@@ -589,7 +875,7 @@ show_menu() {
${green}0.${plain} 退出脚本 ${green}0.${plain} 退出脚本
" "
echo && read -ep "请输入选择 [0-13]: " num echo && read -ep "请输入选择 [0-13]: " num
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
case "${num}" in case "${num}" in
0) 0)
exit 0 exit 0
@@ -637,11 +923,63 @@ show_menu() {
echo -e "${red}请输入正确的数字 [0-13]${plain}" echo -e "${red}请输入正确的数字 [0-13]${plain}"
;; ;;
esac esac
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
case "${num}" in
0)
exit 0
;;
1)
install_dashboard_standalone
;;
2)
modify_dashboard_config_standalone
;;
3)
start_dashboard_standalone
;;
4)
stop_dashboard_standalone
;;
5)
restart_and_update_standalone
;;
6)
show_dashboard_log_standalone
;;
7)
uninstall_dashboard_standalone
;;
8)
install_agent
;;
9)
modify_agent_config
;;
10)
show_agent_log
;;
11)
uninstall_agent
;;
12)
restart_agent
;;
13)
update_script
;;
*)
echo -e "${red}请输入正确的数字 [0-13]${plain}"
;;
esac
else
select_version
fi
} }
pre_check pre_check
if [[ $# > 0 ]]; then if [[ $# > 0 ]]; then
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
case $1 in case $1 in
"install_dashboard") "install_dashboard")
install_dashboard 0 install_dashboard 0
@@ -689,6 +1027,83 @@ if [[ $# > 0 ]]; then
;; ;;
*) show_usage ;; *) show_usage ;;
esac esac
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
case $1 in
"install_dashboard")
install_dashboard_standalone 0
;;
"modify_dashboard_config")
modify_dashboard_config_standalone 0
;;
"start_dashboard")
start_dashboard_standalone 0
;;
"stop_dashboard")
stop_dashboard_standalone 0
;;
"restart_and_update")
restart_and_update_standalone 0
;;
"show_dashboard_log")
show_dashboard_log_standalone 0
;;
"uninstall_dashboard")
uninstall_dashboard_standalone 0
;;
"install_agent")
shift
if [ $# -ge 3 ]; then
install_agent "$@"
else else
install_agent 0
fi
;;
"modify_agent_config")
modify_agent_config 0
;;
"show_agent_log")
show_agent_log 0
;;
"uninstall_agent")
uninstall_agent 0
;;
"restart_agent")
restart_agent 0
;;
"update_script")
update_script 0
;;
*) show_usage ;;
esac
else
case $1 in
"install_agent")
shift
if [ $# -ge 3 ]; then
install_agent "$@"
else
install_agent 0
fi
;;
"modify_agent_config")
modify_agent_config 0
;;
"show_agent_log")
show_agent_log 0
;;
"uninstall_agent")
uninstall_agent 0
;;
"restart_agent")
restart_agent 0
;;
"update_script")
update_script 0
;;
*) show_usage ;;
esac
fi
else
select_version
show_menu show_menu
fi fi
+431 -18
View File
@@ -11,7 +11,10 @@ NZ_BASE_PATH="/opt/nezha"
NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard" NZ_DASHBOARD_PATH="${NZ_BASE_PATH}/dashboard"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent" NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service" NZ_AGENT_SERVICE="/etc/systemd/system/nezha-agent.service"
NZ_VERSION="v0.15.0" NZ_AGENT_SERVICERC="/etc/init.d/nezha-agent"
NZ_DASHBOARD_SERVICE="/etc/systemd/system/nezha-dashboard.service"
NZ_DASHBOARD_SERVICERC="/etc/init.d/nezha-dashboard"
NZ_VERSION="v0.15.3"
red='\033[0;31m' red='\033[0;31m'
green='\033[0;32m' green='\033[0;32m'
@@ -70,18 +73,20 @@ pre_check() {
Get_Docker_URL="get.docker.com" Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" " Get_Docker_Argu=" "
Docker_IMG="ghcr.io\/naiba\/nezha-dashboard" Docker_IMG="ghcr.io\/naiba\/nezha-dashboard"
GITHUB_RELEASE_URL="github.com/naiba/nezha/releases/latest/download"
else else
GITHUB_RAW_URL="jihulab.com/nezha/dashboard/-/raw/master" GITHUB_RAW_URL="gitee.com/naibahq/nezha/raw/master"
GITHUB_URL="dn-dao-github-mirror.daocloud.io" GITHUB_URL="dn-dao-github-mirror.daocloud.io"
Get_Docker_URL="get.daocloud.io/docker" Get_Docker_URL="get.docker.com"
Get_Docker_Argu=" -s docker --mirror Aliyun" Get_Docker_Argu=" -s docker --mirror Aliyun"
Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard" Docker_IMG="registry.cn-shanghai.aliyuncs.com\/naibahq\/nezha-dashboard"
GITHUB_RELEASE_URL="hub.fgit.cf/naiba/nezha/releases/latest/download"
fi fi
} }
confirm() { confirm() {
if [[ $# > 1 ]]; then if [[ $# > 1 ]]; then
echo && read -e -p "$1 [Default$2]: " temp echo && read -e -p "$1 [默认$2]: " temp
if [[ x"${temp}" == x"" ]]; then if [[ x"${temp}" == x"" ]]; then
temp=$2 temp=$2
fi fi
@@ -101,7 +106,7 @@ update_script() {
curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh curl -sL https://${GITHUB_RAW_URL}/script/install_en.sh -o /tmp/nezha.sh
new_version=$(cat /tmp/nezha.sh | grep "NZ_VERSION" | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g') new_version=$(cat /tmp/nezha.sh | grep "NZ_VERSION" | head -n 1 | awk -F "=" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$new_version" ]; then if [ ! -n "$new_version" ]; then
echo -e "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install_en.sh" echo -e "Script failed to get, please check if the network can link https://${GITHUB_RAW_URL}/script/install.sh"
return 1 return 1
fi fi
echo -e "The current latest version is: ${new_version}" echo -e "The current latest version is: ${new_version}"
@@ -121,8 +126,9 @@ before_show_menu() {
install_base() { install_base() {
(command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) || (command -v git >/dev/null 2>&1 && command -v curl >/dev/null 2>&1 && command -v wget >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1) ||
(install_soft curl wget git unzip) (install_soft curl wget git unzip tzdata)
} }
install_arch(){ install_arch(){
echo -e "${green}Info: ${plain} Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually\n" echo -e "${green}Info: ${plain} Archlinux needs to add nezha-agent user to install libselinux. It will be deleted automatically after installation. It is recommended to check manually\n"
read -e -r -p "Do you need to install libselinux? [Y/n] " input read -e -r -p "Do you need to install libselinux? [Y/n] " input
@@ -147,7 +153,6 @@ install_arch(){
esac esac
} }
install_soft() { install_soft() {
(command -v yum >/dev/null 2>&1 && yum makecache && yum install $* selinux-policy -y) || (command -v yum >/dev/null 2>&1 && yum makecache && yum install $* selinux-policy -y) ||
(command -v apt >/dev/null 2>&1 && apt update && apt install $* selinux-utils -y) || (command -v apt >/dev/null 2>&1 && apt update && apt install $* selinux-utils -y) ||
@@ -162,7 +167,7 @@ install_dashboard() {
echo -e "> Install Panel" echo -e "> Install Panel"
# Nezha Monitoring Folder # Nezha Monitoring Folder
if [ ! -d "${NZ_DASHBOARD_PATH}" ]; then if [ ! -d "${NZ_DASHBOARD_PATH}/docker-compose.yaml" ]; then
mkdir -p $NZ_DASHBOARD_PATH mkdir -p $NZ_DASHBOARD_PATH
else else
echo "You may have already installed the dashboard, repeated installation will overwrite the data, please pay attention to backup." echo "You may have already installed the dashboard, repeated installation will overwrite the data, please pay attention to backup."
@@ -203,6 +208,45 @@ install_dashboard() {
fi fi
} }
install_dashboard_standalone() {
install_base
echo -e "> Install Panel"
# Nezha Monitoring Folder
if [ ! -d "${NZ_DASHBOARD_PATH}/app" ]; then
mkdir -p $NZ_DASHBOARD_PATH
else
echo "You may have already installed the dashboard, repeated installation will overwrite the data, please pay attention to backup."
read -e -r -p "Exit the installation? [Y/n] " input
case $input in
[yY][eE][sS] | [yY])
echo "Exit the installation."
exit 0
;;
[nN][oO] | [nN])
echo "Continue."
;;
*)
echo "Exit the installation."
exit 0
;;
esac
fi
if [ ! -d "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" ] || [ ! -d "${NZ_DASHBOARD_PATH}/resource/static/custom" ]; then
mkdir -p "${NZ_DASHBOARD_PATH}/resource/template/theme-custom" "${NZ_DASHBOARD_PATH}/resource/static/custom" >/dev/null 2>&1
fi
chmod 777 -R $NZ_DASHBOARD_PATH
modify_dashboard_config_standalone 0
if [[ $# == 0 ]]; then
before_show_menu
fi
}
selinux(){ selinux(){
#Check SELinux #Check SELinux
if [ "$os_alpine" != 1 ];then if [ "$os_alpine" != 1 ];then
@@ -274,6 +318,13 @@ modify_agent_config() {
echo -e "${red}Fail to download service, please check if the network can link ${GITHUB_RAW_URL}${plain}" echo -e "${red}Fail to download service, please check if the network can link ${GITHUB_RAW_URL}${plain}"
return 0 return 0
fi fi
else
wget -t 2 -T 10 -O $NZ_AGENT_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-agent >/dev/null 2>&1
chmod +x $NZ_AGENT_SERVICERC
if [[ $? != 0 ]]; then
echo -e "${red}Fail to download service, please check if the network can link ${GITHUB_RAW_URL}${plain}"
return 0
fi
fi fi
if [ $# -lt 3 ]; then if [ $# -lt 3 ]; then
@@ -307,8 +358,10 @@ modify_agent_config() {
sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICE} sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICE}
[ -n "${args}" ] && sed -i "/ExecStart/ s/$/ ${args}/" ${NZ_AGENT_SERVICE} [ -n "${args}" ] && sed -i "/ExecStart/ s/$/ ${args}/" ${NZ_AGENT_SERVICE}
else else
echo "@reboot ${NZ_AGENT_PATH}/nezha-agent -s ${nz_grpc_host}:${nz_grpc_port} -p ${nz_client_secret} ${args}" >> /etc/crontabs/root sed -i "s/nz_grpc_host/${nz_grpc_host}/" ${NZ_AGENT_SERVICERC}
crond sed -i "s/nz_grpc_port/${nz_grpc_port}/" ${NZ_AGENT_SERVICERC}
sed -i "s/nz_client_secret/${nz_client_secret}/" ${NZ_AGENT_SERVICERC}
[ -n "${args}" ] && sed -i "/command_args/ s/\"$/ ${args}\"/" ${NZ_AGENT_SERVICERC}
fi fi
echo -e "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}" echo -e "Agent configuration ${green} modified successfully, please wait for agent self-restart to take effect${plain}"
@@ -318,12 +371,13 @@ modify_agent_config() {
systemctl enable nezha-agent systemctl enable nezha-agent
systemctl restart nezha-agent systemctl restart nezha-agent
else else
nohup ${NZ_AGENT_PATH}/nezha-agent -s ${nz_grpc_host}:${nz_grpc_port} -p ${nz_client_secret} ${args} >/dev/null 2>&1 & rc-update add nezha-agent
rc-service nezha-agent restart
fi fi
if [[ $# == 0 ]]; then #if [[ $# == 0 ]]; then
before_show_menu # before_show_menu
fi #fi
} }
modify_dashboard_config() { modify_dashboard_config() {
@@ -392,6 +446,78 @@ modify_dashboard_config() {
fi fi
} }
modify_dashboard_config_standalone() {
echo -e "> Modify Panel Configuration"
echo -e "Download configuration template"
wget -t 2 -T 10 -O /tmp/nezha-config.yaml https://${GITHUB_RAW_URL}/script/config.yaml >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo -e "${red}File failed to get, please check if the network can link ${GITHUB_RAW_URL}${plain}"
return 0
fi
echo "About the GitHub Oauth2 application: create it at https://github.com/settings/developers, no review required, and fill in the http(s)://domain_or_IP/oauth2/callback" &&
echo "(Not recommended) About the Gitee Oauth2 application: create it at https://gitee.com/oauth/applications, no auditing required, and fill in the http(s)://domain_or_IP/oauth2/callback" &&
read -ep "Please enter the OAuth2 provider (github/gitlab/jihulab/gitee, default github): " nz_oauth2_type &&
read -ep "Please enter the Client ID of the Oauth2 application: " nz_github_oauth_client_id &&
read -ep "Please enter the Client Secret of the Oauth2 application: " nz_github_oauth_client_secret &&
read -ep "Please enter your GitHub/Gitee login name as the administrator, separated by commas: " nz_admin_logins &&
read -ep "Please enter the site title: " nz_site_title &&
read -ep "Please enter the site access port: (default 8008)" nz_site_port &&
read -ep "Please enter the RPC port to be used for Agent access: (default 5555)" nz_grpc_port
if [[ -z "${nz_admin_logins}" || -z "${nz_github_oauth_client_id}" || -z "${nz_github_oauth_client_secret}" || -z "${nz_site_title}" ]]; then
echo -e "${red}All options cannot be empty${plain}"
before_show_menu
return 1
fi
if [[ -z "${nz_site_port}" ]]; then
nz_site_port=8008
fi
if [[ -z "${nz_grpc_port}" ]]; then
nz_grpc_port=5555
fi
if [[ -z "${nz_oauth2_type}" ]]; then
nz_oauth2_type=github
fi
sed -i "s/nz_oauth2_type/${nz_oauth2_type}/" /tmp/nezha-config.yaml
sed -i "s/nz_admin_logins/${nz_admin_logins}/" /tmp/nezha-config.yaml
sed -i "s/nz_grpc_port/${nz_grpc_port}/" /tmp/nezha-config.yaml
sed -i "s/nz_github_oauth_client_id/${nz_github_oauth_client_id}/" /tmp/nezha-config.yaml
sed -i "s/nz_github_oauth_client_secret/${nz_github_oauth_client_secret}/" /tmp/nezha-config.yaml
sed -i "s/nz_language/zh-CN/" /tmp/nezha-config.yaml
sed -i "s/nz_site_title/${nz_site_title}/" /tmp/nezha-config.yaml
sed -i "s/80/${nz_site_port}/" /tmp/nezha-config.yaml
mkdir -p $NZ_DASHBOARD_PATH/data
mv -f /tmp/nezha-config.yaml ${NZ_DASHBOARD_PATH}/data/config.yaml
echo -e "Downloading service file"
if [ "$os_alpine" != 1 ];then
wget -t 2 -T 10 -O $NZ_DASHBOARD_SERVICE https://${GITHUB_RAW_URL}/script/nezha-dashboard.service >/dev/null 2>&1
else
wget -t 2 -T 10 -O $NZ_DASHBOARD_SERVICERC https://${GITHUB_RAW_URL}/script/nezha-dashboard >/dev/null 2>&1
chmod +x $NZ_DASHBOARD_SERVICERC
if [[ $? != 0 ]]; then
echo -e "${red}File failed to get, please check if the network can link ${GITHUB_RAW_URL}${plain}"
return 0
fi
fi
echo -e "Dashboard configuration ${green} modified successfully, please wait for Dashboard self-restart to take effect${plain}"
restart_and_update_standalone
if [[ $# == 0 ]]; then
before_show_menu
fi
}
restart_and_update() { restart_and_update() {
echo -e "> Restart and Update the Panel" echo -e "> Restart and Update the Panel"
@@ -420,6 +546,40 @@ restart_and_update() {
fi fi
} }
restart_and_update_standalone() {
echo -e "> Restart and Update the Panel"
cd $NZ_DASHBOARD_PATH
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
wget -qO app.zip $GITHUB_RELEASE_URL/dashboard-linux-$os_arch.zip >/dev/null 2>&1 && unzip -qq app.zip && mv dist/dashboard-linux-$os_arch app && rm -r app.zip dist
if [ "$os_alpine" != 1 ];then
systemctl daemon-reload
systemctl enable nezha-dashboard
systemctl restart nezha-dashboard
else
rc-update add nezha-dashboard
rc-service nezha-dashboard restart
fi
if [[ $? == 0 ]]; then
echo -e "${green}Nezha Monitoring Restart Successful${plain}"
echo -e "Default panel address: ${yellow}domain:Site_access_port${plain}"
else
echo -e "${red}The restart failed, probably because the boot time exceeded two seconds, please check the log information later${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
start_dashboard() { start_dashboard() {
echo -e "> Start Panel" echo -e "> Start Panel"
@@ -441,6 +601,26 @@ start_dashboard() {
fi fi
} }
start_dashboard_standalone() {
echo -e "> Start Panel"
if [ "$os_alpine" != 1 ]; then
systemctl start nezha-dashboard
else
rc-service nezha-dashboard start
fi
if [[ $? == 0 ]]; then
echo -e "${green}Nezha Monitoring Start Successful${plain}"
else
echo -e "${red}Failed to start, please check the log message later${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
stop_dashboard() { stop_dashboard() {
echo -e "> Stop Panel" echo -e "> Stop Panel"
@@ -462,6 +642,26 @@ stop_dashboard() {
fi fi
} }
stop_dashboard_standalone() {
echo -e "> Stop Panel"
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
if [[ $? == 0 ]]; then
echo -e "${green}Nezha Monitoring Stop Successful${plain}"
else
echo -e "${red}Failed to stop, please check the log message later${plain}"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
show_dashboard_log() { show_dashboard_log() {
echo -e "> View Panel Log" echo -e "> View Panel Log"
@@ -477,6 +677,20 @@ show_dashboard_log() {
fi fi
} }
show_dashboard_log_standalone() {
echo -e "> View Panel Log"
if [ "$os_alpine" != 1 ]; then
journalctl -xf -u nezha-dashboard.service
else
echo "Sorry, OpenRC do not have this feature yet."
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
uninstall_dashboard() { uninstall_dashboard() {
echo -e "> Uninstall Panel" echo -e "> Uninstall Panel"
@@ -489,6 +703,31 @@ uninstall_dashboard() {
rm -rf $NZ_DASHBOARD_PATH rm -rf $NZ_DASHBOARD_PATH
docker rmi -f ghcr.io/naiba/nezha-dashboard > /dev/null 2>&1 docker rmi -f ghcr.io/naiba/nezha-dashboard > /dev/null 2>&1
docker rmi -f registry.cn-shanghai.aliyuncs.com/naibahq/nezha-dashboard > /dev/null 2>&1
clean_all
if [[ $# == 0 ]]; then
before_show_menu
fi
}
uninstall_dashboard_standalone() {
echo -e "> Uninstall Panel"
rm -rf $NZ_DASHBOARD_PATH
if [ "$os_alpine" != 1 ]; then
systemctl stop nezha-dashboard
else
rc-service nezha-dashboard stop
fi
if [ "$os_alpine" != 1 ]; then
rm $NZ_DASHBOARD_SERVICE
else
rm $NZ_DASHBOARD_SERVICERC
fi
clean_all clean_all
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
@@ -497,9 +736,13 @@ uninstall_dashboard() {
} }
show_agent_log() { show_agent_log() {
echo -e "> View Agent Log" echo -e "> > View Agent Log"
if [ "$os_alpine" != 1 ]; then
journalctl -xf -u nezha-agent.service journalctl -xf -u nezha-agent.service
else
echo "Sorry, OpenRC do not have this feature yet."
fi
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
@@ -515,8 +758,9 @@ uninstall_agent() {
rm -rf $NZ_AGENT_SERVICE rm -rf $NZ_AGENT_SERVICE
systemctl daemon-reload systemctl daemon-reload
else else
grep -q 'nezha-agent' /var/spool/cron/crontabs/root && sed -i "/nezha-agent/d" /var/spool/cron/crontabs/root rc-update del nezha-agent
pkill nezha-agent rc-service nezha-agent stop
rm -rf $NZ_AGENT_SERVICERC
fi fi
rm -rf $NZ_AGENT_PATH rm -rf $NZ_AGENT_PATH
@@ -530,7 +774,11 @@ uninstall_agent() {
restart_agent() { restart_agent() {
echo -e "> Restart Agent" echo -e "> Restart Agent"
if [ "$os_alpine" != 1 ];then
systemctl restart nezha-agent.service systemctl restart nezha-agent.service
else
rc-service nezha-agent restart
fi
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
@@ -543,6 +791,44 @@ clean_all() {
fi fi
} }
select_version() {
DOCKER_COMPOSE_COMMAND=""
if docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE_COMMAND="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE_COMMAND="docker-compose"
fi
if [[ -n $DOCKER_COMPOSE_COMMAND ]]; then
if $DOCKER_COMPOSE_COMMAND ls | grep -qw "$NZ_DASHBOARD_PATH/docker-compose.yaml" >/dev/null 2>&1; then
IS_DOCKER_NEZHA=1
return
fi
fi
if [[ -f $NZ_DASHBOARD_PATH/app ]]; then
IS_DOCKER_NEZHA=0
else
echo -e "${yellow}Select your installation method(Input anything is ok if you are installing agent):\n1. Docker\n2. Standalone${plain}"
while true; do
read -e -r -p "Input a number [1-2]: " option
case "${option}" in
1)
IS_DOCKER_NEZHA=1
break
;;
2)
IS_DOCKER_NEZHA=0
break
;;
*)
echo "Wrong input, try again"
;;
esac
done
fi
}
show_usage() { show_usage() {
echo "Nezha Monitor Management Script Usage: " echo "Nezha Monitor Management Script Usage: "
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
@@ -587,7 +873,7 @@ show_menu() {
${green}0.${plain} Exit Script ${green}0.${plain} Exit Script
" "
echo && read -ep "Please enter [0-13]: " num echo && read -ep "Please enter [0-13]: " num
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
case "${num}" in case "${num}" in
0) 0)
exit 0 exit 0
@@ -635,11 +921,61 @@ show_menu() {
echo -e "${red}Please enter the correct number [0-13]${plain}" echo -e "${red}Please enter the correct number [0-13]${plain}"
;; ;;
esac esac
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
case "${num}" in
0)
exit 0
;;
1)
install_dashboard_standalone
;;
2)
modify_dashboard_config_standalone
;;
3)
start_dashboard_standalone
;;
4)
stop_dashboard_standalone
;;
5)
restart_and_update_standalone
;;
6)
show_dashboard_log_standalone
;;
7)
uninstall_dashboard_standalone
;;
8)
install_agent
;;
9)
modify_agent_config
;;
10)
show_agent_log
;;
11)
uninstall_agent
;;
12)
restart_agent
;;
13)
update_script
;;
*)
echo -e "${red}Please enter the correct number [0-13]${plain}"
;;
esac
fi
} }
pre_check pre_check
if [[ $# > 0 ]]; then if [[ $# > 0 ]]; then
if [[ $IS_DOCKER_NEZHA == 1 ]]; then
case $1 in case $1 in
"install_dashboard") "install_dashboard")
install_dashboard 0 install_dashboard 0
@@ -687,6 +1023,83 @@ if [[ $# > 0 ]]; then
;; ;;
*) show_usage ;; *) show_usage ;;
esac esac
elif [[ $IS_DOCKER_NEZHA == 0 ]]; then
case $1 in
"install_dashboard")
install_dashboard_standalone 0
;;
"modify_dashboard_config")
modify_dashboard_config_standalone 0
;;
"start_dashboard")
start_dashboard_standalone 0
;;
"stop_dashboard")
stop_dashboard_standalone 0
;;
"restart_and_update")
restart_and_update_standalone 0
;;
"show_dashboard_log")
show_dashboard_log_standalone 0
;;
"uninstall_dashboard")
uninstall_dashboard_standalone 0
;;
"install_agent")
shift
if [ $# -ge 3 ]; then
install_agent "$@"
else else
install_agent 0
fi
;;
"modify_agent_config")
modify_agent_config 0
;;
"show_agent_log")
show_agent_log 0
;;
"uninstall_agent")
uninstall_agent 0
;;
"restart_agent")
restart_agent 0
;;
"update_script")
update_script 0
;;
*) show_usage ;;
esac
else
case $1 in
"install_agent")
shift
if [ $# -ge 3 ]; then
install_agent "$@"
else
install_agent 0
fi
;;
"modify_agent_config")
modify_agent_config 0
;;
"show_agent_log")
show_agent_log 0
;;
"uninstall_agent")
uninstall_agent 0
;;
"restart_agent")
restart_agent 0
;;
"update_script")
update_script 0
;;
*) show_usage ;;
esac
fi
else
select_version
show_menu show_menu
fi fi
+59
View File
@@ -0,0 +1,59 @@
#!/sbin/openrc-run
SERVER="nz_grpc_host:nz_grpc_port" #Dashboard 地址 ip:port
SECRET="nz_client_secret" #SECRET
NZ_BASE_PATH="/opt/nezha"
NZ_AGENT_PATH="${NZ_BASE_PATH}/agent"
pidfile="/run/${RC_SVCNAME}.pid"
command="/opt/nezha/agent/nezha-agent"
command_args="-s ${SERVER} -p ${SECRET}"
command_background=true
depend() {
need net
}
checkconfig() {
GITHUB_URL="github.com"
if [ ! -f "${NZ_AGENT_PATH}/nezha-agent" ]; then
if [[ $(uname -m | grep 'x86_64') != "" ]]; then
os_arch="amd64"
elif [[ $(uname -m | grep 'i386\|i686') != "" ]]; then
os_arch="386"
elif [[ $(uname -m | grep 'aarch64\|armv8b\|armv8l') != "" ]]; then
os_arch="arm64"
elif [[ $(uname -m | grep 'arm') != "" ]]; then
os_arch="arm"
elif [[ $(uname -m | grep 's390x') != "" ]]; then
os_arch="s390x"
elif [[ $(uname -m | grep 'riscv64') != "" ]]; then
os_arch="riscv64"
fi
local version=$(curl -m 10 -sL "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
if [ ! -n "$version" ]; then
version=$(curl -m 10 -sL "https://fastly.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi
if [ ! -n "$version" ]; then
version=$(curl -m 10 -sL "https://gcore.jsdelivr.net/gh/nezhahq/agent/" | grep "option\.value" | awk -F "'" '{print $2}' | sed 's/nezhahq\/agent@/v/g')
fi
if [ ! -n "$version" ]; then
echo -e "获取版本号失败,请检查本机能否链接 https://api.github.com/repos/nezhahq/agent/releases/latest"
return 0
else
echo -e "当前最新版本为: ${version}"
fi
wget -t 2 -T 10 -O nezha-agent_linux_${os_arch}.zip https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_linux_${os_arch}.zip >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo -e "Release 下载失败,请检查本机能否连接 ${GITHUB_URL}${plain}"
return 0
fi
mkdir -p $NZ_AGENT_PATH
chmod 755 -R $NZ_AGENT_PATH
unzip -qo nezha-agent_linux_${os_arch}.zip && mv nezha-agent $NZ_AGENT_PATH && rm -rf nezha-agent_linux_${os_arch}.zip README.md
fi
if [ ! -x "${NZ_AGENT_PATH}/nezha-agent" ]; then
chmod +x ${NZ_AGENT_PATH}/nezha-agent
fi
}
start_pre() {
if [ "${RC_CMD}" != "restart" ]; then
checkconfig || return $?
fi
}
+16
View File
@@ -0,0 +1,16 @@
#!/sbin/openrc-run
pidfile="/run/${RC_SVCNAME}.pid"
command="/opt/nezha/dashboard/app"
command_args=""
command_background=true
directory="/opt/nezha/dashboard"
depend() {
need net
}
reload() {
ebegin "Reloading ${RC_SVCNAME}"
start-stop-daemon --signal HUP --pidfile "${pidfile}"
eend $?
}
+3 -3
View File
@@ -1,5 +1,5 @@
[Unit] [Unit]
Description=Nezha Dashborad Description=Nezha Dashboard
After=syslog.target After=syslog.target
After=network.target After=network.target
After=mariadb.service mysqld.service postgresql.service memcached.service redis.service After=mariadb.service mysqld.service postgresql.service memcached.service redis.service
@@ -14,8 +14,8 @@ After=mariadb.service mysqld.service postgresql.service memcached.service redis.
Type=simple Type=simple
#User=root #User=root
#Group=root #Group=root
WorkingDirectory=/root/nezha/dashboard/ WorkingDirectory=/opt/nezha/dashboard/
ExecStart=/root/nezha/dashboard/nezha-dashboard-linux-amd64 ExecStart=/opt/nezha/dashboard/app
Restart=always Restart=always
#Environment=DEBUG=true #Environment=DEBUG=true