mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 20:58:14 -05:00
💥 v2.0 必须更新面板,新增服务监控
This commit is contained in:
parent
0ce8017875
commit
a41c792577
@ -3,7 +3,7 @@ RUN apk --no-cache --no-progress add \
|
|||||||
gcc git musl-dev
|
gcc git musl-dev
|
||||||
WORKDIR /dashboard
|
WORKDIR /dashboard
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN cd cmd/dashboard && go build -o app -ldflags="-s -w -X github.com/naiba/nezha/service/dao.Version=$(git rev-parse HEAD)"
|
RUN cd cmd/dashboard && go build -o app -ldflags="-s -w"
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
RUN apk --no-cache --no-progress add \
|
RUN apk --no-cache --no-progress add \
|
||||||
|
10
README.md
10
README.md
@ -179,3 +179,13 @@ URL 里面也可放置占位符,请求时会进行简单的字符串替换。
|
|||||||
- [哪吒面板,一个便携服务器状态监控面板搭建教程,不想拥有一个自己的探针吗?](https://haoduck.com/644.html)
|
- [哪吒面板,一个便携服务器状态监控面板搭建教程,不想拥有一个自己的探针吗?](https://haoduck.com/644.html)
|
||||||
- [哪吒面板:小鸡们的最佳探针](https://www.zhujizixun.com/2843.html) *(已过时)*
|
- [哪吒面板:小鸡们的最佳探针](https://www.zhujizixun.com/2843.html) *(已过时)*
|
||||||
- [>>更多教程](https://www.google.com/search?q=%22%E5%93%AA%E5%90%92%E9%9D%A2%E6%9D%BF%22+%22%E6%95%99%E7%A8%8B%22) (Google)
|
- [>>更多教程](https://www.google.com/search?q=%22%E5%93%AA%E5%90%92%E9%9D%A2%E6%9D%BF%22+%22%E6%95%99%E7%A8%8B%22) (Google)
|
||||||
|
|
||||||
|
## 变更日志
|
||||||
|
|
||||||
|
- `0.2.0` **重大更新**
|
||||||
|
|
||||||
|
增加了服务监控(TCP端口延迟、Ping、HTTP-SSL 证书)功能,此版本 Agent 与旧面板不兼容,而 Agent 是通过 GitHub Release 自动更新的 所以务必更新面板开启最新功能。
|
||||||
|
|
||||||
|
- `0.1.23` 新增 IP 变更通知功能
|
||||||
|
|
||||||
|
在后台设置界面启用。
|
||||||
|
@ -2,13 +2,18 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
|
"github.com/genkiroid/cert"
|
||||||
|
"github.com/go-ping/ping"
|
||||||
"github.com/p14yground/go-github-selfupdate/selfupdate"
|
"github.com/p14yground/go-github-selfupdate/selfupdate"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@ -105,7 +110,6 @@ func run(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
var conn *grpc.ClientConn
|
var conn *grpc.ClientConn
|
||||||
var hc pb.NezhaService_HeartbeatClient
|
|
||||||
|
|
||||||
retry := func() {
|
retry := func() {
|
||||||
log.Println("Error to close connection ...")
|
log.Println("Error to close connection ...")
|
||||||
@ -125,44 +129,91 @@ func run(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
client = pb.NewNezhaServiceClient(conn)
|
client = pb.NewNezhaServiceClient(conn)
|
||||||
// 第一步注册
|
// 第一步注册
|
||||||
_, err = client.Register(ctx, monitor.GetHost().PB())
|
_, err = client.ReportSystemInfo(ctx, monitor.GetHost().PB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("client.Register err: %v", err)
|
log.Printf("client.ReportSystemInfo err: %v", err)
|
||||||
retry()
|
retry()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 心跳接收控制命令
|
// 执行 Task
|
||||||
hc, err = client.Heartbeat(ctx, &pb.Beat{
|
tasks, err := client.RequestTask(ctx, monitor.GetHost().PB())
|
||||||
Timestamp: fmt.Sprintf("%v", time.Now()),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("client.Heartbeat err: %v", err)
|
log.Printf("client.RequestTask err: %v", err)
|
||||||
retry()
|
retry()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = receiveCommand(hc)
|
err = receiveTasks(tasks)
|
||||||
log.Printf("receiveCommand exit to main: %v", err)
|
log.Printf("receiveCommand exit to main: %v", err)
|
||||||
retry()
|
retry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func receiveCommand(hc pb.NezhaService_HeartbeatClient) error {
|
func receiveTasks(tasks pb.NezhaService_RequestTaskClient) error {
|
||||||
var err error
|
var err error
|
||||||
var action *pb.Command
|
var task *pb.Task
|
||||||
defer log.Printf("receiveCommand exit %v %v => %v", time.Now(), action, err)
|
defer log.Printf("receiveTasks exit %v %v => %v", time.Now(), task, err)
|
||||||
for {
|
for {
|
||||||
action, err = hc.Recv()
|
task, err = tasks.Recv()
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch action.GetType() {
|
var result pb.TaskResult
|
||||||
default:
|
result.Id = task.GetId()
|
||||||
log.Printf("Unknown action: %v", action)
|
switch task.GetType() {
|
||||||
|
case model.MonitorTypeHTTPGET:
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := http.Get(task.GetData())
|
||||||
|
if err == nil {
|
||||||
|
result.Delay = float32(time.Now().Sub(start).Microseconds()) / 1000.0
|
||||||
|
if resp.StatusCode > 299 || resp.StatusCode < 200 {
|
||||||
|
err = errors.New("\n应用错误:" + resp.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var certs cert.Certs
|
||||||
|
if err == nil {
|
||||||
|
if strings.HasPrefix(task.GetData(), "https://") {
|
||||||
|
certs, err = cert.NewCerts([]string{task.GetData()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if len(certs) == 0 {
|
||||||
|
err = errors.New("\n获取SSL证书错误:未获取到证书")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
result.Data = certs[0].Issuer
|
||||||
|
result.Successful = true
|
||||||
|
} else {
|
||||||
|
result.Data = err.Error()
|
||||||
|
}
|
||||||
|
case model.MonitorTypeICMPPing:
|
||||||
|
pinger, err := ping.NewPinger(task.GetData())
|
||||||
|
if err == nil {
|
||||||
|
pinger.Count = 10
|
||||||
|
err = pinger.Run() // Blocks until finished.
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
stat := pinger.Statistics()
|
||||||
|
result.Delay = float32(stat.AvgRtt.Microseconds()) / 1000.0
|
||||||
|
result.Successful = true
|
||||||
|
} else {
|
||||||
|
result.Data = err.Error()
|
||||||
|
}
|
||||||
|
case model.MonitorTypeTCPPing:
|
||||||
|
start := time.Now()
|
||||||
|
conn, err := net.DialTimeout("tcp", task.GetData(), time.Second*10)
|
||||||
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
|
result.Delay = float32(time.Now().Sub(start).Microseconds()) / 1000.0
|
||||||
|
result.Successful = true
|
||||||
|
} else {
|
||||||
|
result.Data = err.Error()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Printf("Unknown action: %v", task)
|
||||||
|
}
|
||||||
|
client.ReportTask(ctx, &result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportState() {
|
func reportState() {
|
||||||
@ -172,14 +223,14 @@ func reportState() {
|
|||||||
for {
|
for {
|
||||||
if client != nil {
|
if client != nil {
|
||||||
monitor.TrackNetworkSpeed()
|
monitor.TrackNetworkSpeed()
|
||||||
_, err = client.ReportState(ctx, monitor.GetState(dao.ReportDelay).PB())
|
_, err = client.ReportSystemState(ctx, monitor.GetState(dao.ReportDelay).PB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("reportState error %v", err)
|
log.Printf("reportState error %v", err)
|
||||||
time.Sleep(delayWhenError)
|
time.Sleep(delayWhenError)
|
||||||
}
|
}
|
||||||
if lastReportHostInfo.Before(time.Now().Add(-10 * time.Minute)) {
|
if lastReportHostInfo.Before(time.Now().Add(-10 * time.Minute)) {
|
||||||
lastReportHostInfo = time.Now()
|
lastReportHostInfo = time.Now()
|
||||||
client.Register(ctx, monitor.GetHost().PB())
|
client.ReportSystemInfo(ctx, monitor.GetHost().PB())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,64 @@ func (cp *commonPage) serve() {
|
|||||||
cr := cp.r.Group("")
|
cr := cp.r.Group("")
|
||||||
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
|
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
|
||||||
cr.GET("/", cp.home)
|
cr.GET("/", cp.home)
|
||||||
|
cr.GET("/service", cp.service)
|
||||||
cr.GET("/ws", cp.ws)
|
cr.GET("/ws", cp.ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServiceItem struct {
|
||||||
|
Monitor model.Monitor
|
||||||
|
TotalUp uint64
|
||||||
|
TotalDown uint64
|
||||||
|
Delay *[30]float32
|
||||||
|
Up *[30]int
|
||||||
|
Down *[30]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *commonPage) service(c *gin.Context) {
|
||||||
|
var ms []model.Monitor
|
||||||
|
dao.DB.Find(&ms)
|
||||||
|
year, month, day := time.Now().Date()
|
||||||
|
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
||||||
|
var mhs []model.MonitorHistory
|
||||||
|
dao.DB.Where("created_at >= ?", today.AddDate(0, 0, -29)).Find(&mhs)
|
||||||
|
|
||||||
|
msm := make(map[uint64]*ServiceItem)
|
||||||
|
for i := 0; i < len(ms); i++ {
|
||||||
|
msm[ms[i].ID] = &ServiceItem{
|
||||||
|
Monitor: ms[i],
|
||||||
|
Delay: &[30]float32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
Up: &[30]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
Down: &[30]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 整合数据
|
||||||
|
for i := 0; i < len(mhs); i++ {
|
||||||
|
dayIndex := 29
|
||||||
|
if mhs[i].CreatedAt.Before(today) {
|
||||||
|
dayIndex = 28 - (int(today.Sub(mhs[i].CreatedAt).Hours()) / 24)
|
||||||
|
}
|
||||||
|
if mhs[i].Successful {
|
||||||
|
msm[mhs[i].MonitorID].TotalUp++
|
||||||
|
msm[mhs[i].MonitorID].Delay[dayIndex] = (msm[mhs[i].MonitorID].Delay[dayIndex]*float32(msm[mhs[i].MonitorID].Up[dayIndex]) + mhs[i].Delay) / float32(msm[mhs[i].MonitorID].Up[dayIndex]+1)
|
||||||
|
msm[mhs[i].MonitorID].Up[dayIndex]++
|
||||||
|
} else {
|
||||||
|
msm[mhs[i].MonitorID].TotalDown++
|
||||||
|
msm[mhs[i].MonitorID].Down[dayIndex]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u, ok := c.Get(model.CtxKeyAuthorizedUser)
|
||||||
|
data := mygin.CommonEnvironment(c, gin.H{
|
||||||
|
"Title": "服务状态",
|
||||||
|
"Services": msm,
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
data["Admin"] = u
|
||||||
|
}
|
||||||
|
c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/service", data)
|
||||||
|
}
|
||||||
|
|
||||||
func (cp *commonPage) home(c *gin.Context) {
|
func (cp *commonPage) home(c *gin.Context) {
|
||||||
dao.ServerLock.RLock()
|
dao.ServerLock.RLock()
|
||||||
defer dao.ServerLock.RUnlock()
|
defer dao.ServerLock.RUnlock()
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/naiba/nezha/service/dao"
|
"github.com/naiba/nezha/service/dao"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServeWeb ..
|
|
||||||
func ServeWeb(port uint) {
|
func ServeWeb(port uint) {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
if dao.Conf.Debug {
|
if dao.Conf.Debug {
|
||||||
@ -43,6 +42,35 @@ func ServeWeb(port uint) {
|
|||||||
"ts": func(s string) string {
|
"ts": func(s string) string {
|
||||||
return strings.TrimSpace(s)
|
return strings.TrimSpace(s)
|
||||||
},
|
},
|
||||||
|
"divU64": func(a, b uint64) float32 {
|
||||||
|
if b == 0 {
|
||||||
|
if a > 0 {
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float32(a) / float32(b) * 100
|
||||||
|
},
|
||||||
|
"div": func(a, b int) float32 {
|
||||||
|
if b == 0 {
|
||||||
|
if a > 0 {
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float32(a) / float32(b) * 100
|
||||||
|
},
|
||||||
|
"addU64": func(a, b uint64) uint64 {
|
||||||
|
return a + b
|
||||||
|
},
|
||||||
|
"add": func(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
},
|
||||||
|
"dayBefore": func(i int) string {
|
||||||
|
year, month, day := time.Now().Date()
|
||||||
|
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
||||||
|
return today.AddDate(0, 0, i-29).Format("1月2号")
|
||||||
|
},
|
||||||
})
|
})
|
||||||
r.Static("/static", "resource/static")
|
r.Static("/static", "resource/static")
|
||||||
r.LoadHTMLGlob("resource/template/**/*")
|
r.LoadHTMLGlob("resource/template/**/*")
|
||||||
|
@ -33,6 +33,7 @@ func (ma *memberAPI) serve() {
|
|||||||
|
|
||||||
mr.POST("/logout", ma.logout)
|
mr.POST("/logout", ma.logout)
|
||||||
mr.POST("/server", ma.addOrEditServer)
|
mr.POST("/server", ma.addOrEditServer)
|
||||||
|
mr.POST("/monitor", ma.addOrEditMonitor)
|
||||||
mr.POST("/notification", ma.addOrEditNotification)
|
mr.POST("/notification", ma.addOrEditNotification)
|
||||||
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
||||||
mr.POST("/setting", ma.updateSetting)
|
mr.POST("/setting", ma.updateSetting)
|
||||||
@ -64,6 +65,8 @@ func (ma *memberAPI) delete(c *gin.Context) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
alertmanager.OnDeleteNotification(id)
|
alertmanager.OnDeleteNotification(id)
|
||||||
}
|
}
|
||||||
|
case "monitor":
|
||||||
|
err = dao.DB.Delete(&model.Monitor{}, "id = ?", id).Error
|
||||||
case "alert-rule":
|
case "alert-rule":
|
||||||
err = dao.DB.Delete(&model.AlertRule{}, "id = ?", id).Error
|
err = dao.DB.Delete(&model.AlertRule{}, "id = ?", id).Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -125,7 +128,7 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
|
|||||||
s.State = dao.ServerList[s.ID].State
|
s.State = dao.ServerList[s.ID].State
|
||||||
} else {
|
} else {
|
||||||
s.Host = &model.Host{}
|
s.Host = &model.Host{}
|
||||||
s.State = &model.State{}
|
s.State = &model.HostState{}
|
||||||
}
|
}
|
||||||
dao.ServerList[s.ID] = &s
|
dao.ServerList[s.ID] = &s
|
||||||
dao.ReSortServer()
|
dao.ReSortServer()
|
||||||
@ -134,6 +137,42 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type monitorForm struct {
|
||||||
|
ID uint64
|
||||||
|
Name string
|
||||||
|
Target string
|
||||||
|
Type uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
|
||||||
|
var mf monitorForm
|
||||||
|
var m model.Monitor
|
||||||
|
err := c.ShouldBindJSON(&mf)
|
||||||
|
if err == nil {
|
||||||
|
m.Name = mf.Name
|
||||||
|
m.Target = mf.Target
|
||||||
|
m.Type = mf.Type
|
||||||
|
m.ID = mf.ID
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if m.ID == 0 {
|
||||||
|
err = dao.DB.Create(&m).Error
|
||||||
|
} else {
|
||||||
|
err = dao.DB.Save(&m).Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
Message: fmt.Sprintf("请求错误:%s", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, model.Response{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type notificationForm struct {
|
type notificationForm struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
Name string
|
Name string
|
||||||
|
@ -23,6 +23,7 @@ func (mp *memberPage) serve() {
|
|||||||
Redirect: "/login",
|
Redirect: "/login",
|
||||||
}))
|
}))
|
||||||
mr.GET("/server", mp.server)
|
mr.GET("/server", mp.server)
|
||||||
|
mr.GET("/monitor", mp.monitor)
|
||||||
mr.GET("/notification", mp.notification)
|
mr.GET("/notification", mp.notification)
|
||||||
mr.GET("/setting", mp.setting)
|
mr.GET("/setting", mp.setting)
|
||||||
}
|
}
|
||||||
@ -36,6 +37,15 @@ func (mp *memberPage) server(c *gin.Context) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *memberPage) monitor(c *gin.Context) {
|
||||||
|
var monitors []model.Monitor
|
||||||
|
dao.DB.Find(&monitors)
|
||||||
|
c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{
|
||||||
|
"Title": "服务监控",
|
||||||
|
"Monitors": monitors,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func (mp *memberPage) notification(c *gin.Context) {
|
func (mp *memberPage) notification(c *gin.Context) {
|
||||||
var nf []model.Notification
|
var nf []model.Notification
|
||||||
dao.DB.Find(&nf)
|
dao.DB.Find(&nf)
|
||||||
|
@ -34,14 +34,16 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initDB() {
|
func initDB() {
|
||||||
dao.DB.AutoMigrate(model.Server{}, model.User{}, model.Notification{}, model.AlertRule{})
|
dao.DB.AutoMigrate(model.Server{}, model.User{},
|
||||||
|
model.Notification{}, model.AlertRule{}, model.Monitor{},
|
||||||
|
model.MonitorHistory{})
|
||||||
// load cache
|
// load cache
|
||||||
var servers []model.Server
|
var servers []model.Server
|
||||||
dao.DB.Find(&servers)
|
dao.DB.Find(&servers)
|
||||||
for _, s := range servers {
|
for _, s := range servers {
|
||||||
innerS := s
|
innerS := s
|
||||||
innerS.Host = &model.Host{}
|
innerS.Host = &model.Host{}
|
||||||
innerS.State = &model.State{}
|
innerS.State = &model.HostState{}
|
||||||
dao.ServerList[innerS.ID] = &innerS
|
dao.ServerList[innerS.ID] = &innerS
|
||||||
}
|
}
|
||||||
dao.ReSortServer()
|
dao.ReSortServer()
|
||||||
@ -50,5 +52,6 @@ func initDB() {
|
|||||||
func main() {
|
func main() {
|
||||||
go controller.ServeWeb(dao.Conf.HTTPPort)
|
go controller.ServeWeb(dao.Conf.HTTPPort)
|
||||||
go rpc.ServeRPC(5555)
|
go rpc.ServeRPC(5555)
|
||||||
|
go rpc.DispatchTask(time.Minute * 10)
|
||||||
alertmanager.Start()
|
alertmanager.Start()
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,18 @@ package rpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/model"
|
||||||
pb "github.com/naiba/nezha/proto"
|
pb "github.com/naiba/nezha/proto"
|
||||||
|
"github.com/naiba/nezha/service/dao"
|
||||||
rpcService "github.com/naiba/nezha/service/rpc"
|
rpcService "github.com/naiba/nezha/service/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServeRPC ...
|
|
||||||
func ServeRPC(port uint) {
|
func ServeRPC(port uint) {
|
||||||
server := grpc.NewServer()
|
server := grpc.NewServer()
|
||||||
pb.RegisterNezhaServiceServer(server, &rpcService.NezhaHandler{
|
pb.RegisterNezhaServiceServer(server, &rpcService.NezhaHandler{
|
||||||
@ -22,3 +25,34 @@ func ServeRPC(port uint) {
|
|||||||
}
|
}
|
||||||
server.Serve(listen)
|
server.Serve(listen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DispatchTask(duration time.Duration) {
|
||||||
|
var index uint64 = 0
|
||||||
|
for {
|
||||||
|
var tasks []model.Monitor
|
||||||
|
var hasAliveAgent bool
|
||||||
|
dao.DB.Find(&tasks)
|
||||||
|
dao.ServerLock.RLock()
|
||||||
|
for i := 0; i < len(tasks); i++ {
|
||||||
|
if index >= uint64(len(dao.SortedServerList)) {
|
||||||
|
index = 0
|
||||||
|
if !hasAliveAgent {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hasAliveAgent = false
|
||||||
|
}
|
||||||
|
if dao.SortedServerList[index].TaskStream == nil {
|
||||||
|
i--
|
||||||
|
index++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hasAliveAgent = true
|
||||||
|
log.Println("DispatchTask 确认派发 >>>>>", i, index)
|
||||||
|
dao.SortedServerList[index].TaskStream.Send(tasks[i].PB())
|
||||||
|
log.Println("DispatchTask 确认派发 <<<<<", i, index)
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
dao.ServerLock.RUnlock()
|
||||||
|
time.Sleep(duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/genkiroid/cert"
|
||||||
|
"github.com/go-ping/ping"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
conn, err := net.DialTimeout("tcp", "example.com:80", time.Second*10)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
println(conn)
|
||||||
|
pinger, err := ping.NewPinger("example.com")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pinger.Count = 3
|
||||||
|
err = pinger.Run() // Blocks until finished.
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%+v", pinger.Statistics())
|
||||||
|
certs, err := cert.NewCerts([]string{"example.com"})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println(certs)
|
||||||
dparts, _ := disk.Partitions(false)
|
dparts, _ := disk.Partitions(false)
|
||||||
for _, part := range dparts {
|
for _, part := range dparts {
|
||||||
u, _ := disk.Usage(part.Mountpoint)
|
u, _ := disk.Usage(part.Mountpoint)
|
||||||
@ -18,12 +43,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cmdExec() {
|
func cmdExec() {
|
||||||
cmd := exec.Command("ping", "qiongbi.net", "-c2")
|
cmd := exec.Command("ping", "example.com", "-c2")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
log.Println("output:", string(output))
|
log.Println("output:", string(output))
|
||||||
log.Println("err:", err)
|
log.Println("err:", err)
|
||||||
|
|
||||||
cmd = exec.Command("ping", "qiongbi", "-c2")
|
cmd = exec.Command("ping", "example", "-c2")
|
||||||
output, err = cmd.Output()
|
output, err = cmd.Output()
|
||||||
log.Println("output:", string(output))
|
log.Println("output:", string(output))
|
||||||
log.Println("err:", err)
|
log.Println("err:", err)
|
||||||
|
2
go.mod
2
go.mod
@ -6,7 +6,9 @@ require (
|
|||||||
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
|
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
|
||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
|
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50
|
||||||
github.com/gin-gonic/gin v1.6.3
|
github.com/gin-gonic/gin v1.6.3
|
||||||
|
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663
|
||||||
github.com/golang/protobuf v1.4.2
|
github.com/golang/protobuf v1.4.2
|
||||||
github.com/google/go-github v17.0.0+incompatible
|
github.com/google/go-github v17.0.0+incompatible
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
|
6
go.sum
6
go.sum
@ -83,6 +83,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50 h1:vLwmYBduhnWWqShoUGbVgDulhcLdanoYtCQxYMzwaqQ=
|
||||||
|
github.com/genkiroid/cert v0.0.0-20191007122723-897560fbbe50/go.mod h1:Pb7nyGYAfDyE/IkU6AJeRshIFko0wJC9cOqeYzYQffk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
@ -96,6 +98,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
|||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
|
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663 h1:jI2GiiRh+pPbey52EVmbU6kuLiXqwy4CXZ4gwUBj8Y0=
|
||||||
|
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI=
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
@ -417,6 +421,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
||||||
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -118,7 +118,7 @@ func (r *AlertRule) Check(points [][]interface{}) (int, string) {
|
|||||||
fail++
|
fail++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fail/total > 0.3 {
|
if fail/total > 0.5 {
|
||||||
count++
|
count++
|
||||||
dist.WriteString(fmt.Sprintf("%+v\n", r.Rules[i]))
|
dist.WriteString(fmt.Sprintf("%+v\n", r.Rules[i]))
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,10 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// CtxKeyAuthorizedUser ..
|
|
||||||
const CtxKeyAuthorizedUser = "ckau"
|
const CtxKeyAuthorizedUser = "ckau"
|
||||||
|
|
||||||
// CtxKeyOauth2State ..
|
|
||||||
const CtxKeyOauth2State = "cko2s"
|
const CtxKeyOauth2State = "cko2s"
|
||||||
|
|
||||||
// Common ..
|
|
||||||
type Common struct {
|
type Common struct {
|
||||||
ID uint64 `gorm:"primary_key"`
|
ID uint64 `gorm:"primary_key"`
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
@ -16,7 +13,6 @@ type Common struct {
|
|||||||
DeletedAt *time.Time `sql:"index"`
|
DeletedAt *time.Time `sql:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response ..
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Code uint64 `json:"code,omitempty"`
|
Code uint64 `json:"code,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
|
@ -29,7 +29,6 @@ type Config struct {
|
|||||||
v *viper.Viper
|
v *viper.Viper
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadInConfig ..
|
|
||||||
func (c *Config) Read(path string) error {
|
func (c *Config) Read(path string) error {
|
||||||
c.v = viper.New()
|
c.v = viper.New()
|
||||||
c.v.SetConfigFile(path)
|
c.v.SetConfigFile(path)
|
||||||
|
114
model/host.go
Normal file
114
model/host.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
pb "github.com/naiba/nezha/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
|
||||||
|
MTReportHostState
|
||||||
|
)
|
||||||
|
|
||||||
|
type HostState struct {
|
||||||
|
CPU float64
|
||||||
|
MemUsed uint64
|
||||||
|
SwapUsed uint64
|
||||||
|
DiskUsed uint64
|
||||||
|
NetInTransfer uint64
|
||||||
|
NetOutTransfer uint64
|
||||||
|
NetInSpeed uint64
|
||||||
|
NetOutSpeed uint64
|
||||||
|
Uptime uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HostState) PB() *pb.State {
|
||||||
|
return &pb.State{
|
||||||
|
Cpu: s.CPU,
|
||||||
|
MemUsed: s.MemUsed,
|
||||||
|
SwapUsed: s.SwapUsed,
|
||||||
|
DiskUsed: s.DiskUsed,
|
||||||
|
NetInTransfer: s.NetInTransfer,
|
||||||
|
NetOutTransfer: s.NetOutTransfer,
|
||||||
|
NetInSpeed: s.NetInSpeed,
|
||||||
|
NetOutSpeed: s.NetOutSpeed,
|
||||||
|
Uptime: s.Uptime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PB2State(s *pb.State) HostState {
|
||||||
|
return HostState{
|
||||||
|
CPU: s.GetCpu(),
|
||||||
|
MemUsed: s.GetMemUsed(),
|
||||||
|
SwapUsed: s.GetSwapUsed(),
|
||||||
|
DiskUsed: s.GetDiskUsed(),
|
||||||
|
NetInTransfer: s.GetNetInTransfer(),
|
||||||
|
NetOutTransfer: s.GetNetOutTransfer(),
|
||||||
|
NetInSpeed: s.GetNetInSpeed(),
|
||||||
|
NetOutSpeed: s.GetNetOutSpeed(),
|
||||||
|
Uptime: s.GetUptime(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Host struct {
|
||||||
|
Platform string
|
||||||
|
PlatformVersion string
|
||||||
|
CPU []string
|
||||||
|
MemTotal uint64
|
||||||
|
DiskTotal uint64
|
||||||
|
SwapTotal uint64
|
||||||
|
Arch string
|
||||||
|
Virtualization string
|
||||||
|
BootTime uint64
|
||||||
|
IP string `json:"-"`
|
||||||
|
CountryCode string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Host) PB() *pb.Host {
|
||||||
|
return &pb.Host{
|
||||||
|
Platform: h.Platform,
|
||||||
|
PlatformVersion: h.PlatformVersion,
|
||||||
|
Cpu: h.CPU,
|
||||||
|
MemTotal: h.MemTotal,
|
||||||
|
DiskTotal: h.DiskTotal,
|
||||||
|
SwapTotal: h.SwapTotal,
|
||||||
|
Arch: h.Arch,
|
||||||
|
Virtualization: h.Virtualization,
|
||||||
|
BootTime: h.BootTime,
|
||||||
|
Ip: h.IP,
|
||||||
|
CountryCode: h.CountryCode,
|
||||||
|
Version: h.Version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PB2Host(h *pb.Host) Host {
|
||||||
|
|
||||||
|
cpuCount := make(map[string]int, 0)
|
||||||
|
cpus := h.GetCpu()
|
||||||
|
for _, u := range cpus {
|
||||||
|
cpuCount[u]++
|
||||||
|
}
|
||||||
|
|
||||||
|
var distCpu []string
|
||||||
|
for u, num := range cpuCount {
|
||||||
|
distCpu = append(distCpu, fmt.Sprintf("%sx%d", u, num))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Host{
|
||||||
|
Platform: h.GetPlatform(),
|
||||||
|
PlatformVersion: h.GetPlatformVersion(),
|
||||||
|
CPU: distCpu,
|
||||||
|
MemTotal: h.GetMemTotal(),
|
||||||
|
DiskTotal: h.GetDiskTotal(),
|
||||||
|
SwapTotal: h.GetSwapTotal(),
|
||||||
|
Arch: h.GetArch(),
|
||||||
|
Virtualization: h.GetVirtualization(),
|
||||||
|
BootTime: h.GetBootTime(),
|
||||||
|
IP: h.GetIp(),
|
||||||
|
CountryCode: h.GetCountryCode(),
|
||||||
|
Version: h.GetVersion(),
|
||||||
|
}
|
||||||
|
}
|
119
model/monitor.go
119
model/monitor.go
@ -1,120 +1,27 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
pb "github.com/naiba/nezha/proto"
|
pb "github.com/naiba/nezha/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ = iota
|
_ = iota
|
||||||
// MTReportState ..
|
MonitorTypeHTTPGET
|
||||||
MTReportState
|
MonitorTypeICMPPing
|
||||||
|
MonitorTypeTCPPing
|
||||||
)
|
)
|
||||||
|
|
||||||
// State ..
|
type Monitor struct {
|
||||||
type State struct {
|
Common
|
||||||
CPU float64
|
Name string
|
||||||
MemUsed uint64
|
Type uint8
|
||||||
SwapUsed uint64
|
Target string
|
||||||
DiskUsed uint64
|
|
||||||
NetInTransfer uint64
|
|
||||||
NetOutTransfer uint64
|
|
||||||
NetInSpeed uint64
|
|
||||||
NetOutSpeed uint64
|
|
||||||
Uptime uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PB ..
|
func (m *Monitor) PB() *pb.Task {
|
||||||
func (s *State) PB() *pb.State {
|
return &pb.Task{
|
||||||
return &pb.State{
|
Id: m.ID,
|
||||||
Cpu: s.CPU,
|
Type: uint64(m.Type),
|
||||||
MemUsed: s.MemUsed,
|
Data: m.Target,
|
||||||
SwapUsed: s.SwapUsed,
|
|
||||||
DiskUsed: s.DiskUsed,
|
|
||||||
NetInTransfer: s.NetInTransfer,
|
|
||||||
NetOutTransfer: s.NetOutTransfer,
|
|
||||||
NetInSpeed: s.NetInSpeed,
|
|
||||||
NetOutSpeed: s.NetOutSpeed,
|
|
||||||
Uptime: s.Uptime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PB2State ..
|
|
||||||
func PB2State(s *pb.State) State {
|
|
||||||
return State{
|
|
||||||
CPU: s.GetCpu(),
|
|
||||||
MemUsed: s.GetMemUsed(),
|
|
||||||
SwapUsed: s.GetSwapUsed(),
|
|
||||||
DiskUsed: s.GetDiskUsed(),
|
|
||||||
NetInTransfer: s.GetNetInTransfer(),
|
|
||||||
NetOutTransfer: s.GetNetOutTransfer(),
|
|
||||||
NetInSpeed: s.GetNetInSpeed(),
|
|
||||||
NetOutSpeed: s.GetNetOutSpeed(),
|
|
||||||
Uptime: s.GetUptime(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host ..
|
|
||||||
type Host struct {
|
|
||||||
Platform string
|
|
||||||
PlatformVersion string
|
|
||||||
CPU []string
|
|
||||||
MemTotal uint64
|
|
||||||
DiskTotal uint64
|
|
||||||
SwapTotal uint64
|
|
||||||
Arch string
|
|
||||||
Virtualization string
|
|
||||||
BootTime uint64
|
|
||||||
IP string `json:"-"`
|
|
||||||
CountryCode string
|
|
||||||
Version string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PB ..
|
|
||||||
func (h *Host) PB() *pb.Host {
|
|
||||||
return &pb.Host{
|
|
||||||
Platform: h.Platform,
|
|
||||||
PlatformVersion: h.PlatformVersion,
|
|
||||||
Cpu: h.CPU,
|
|
||||||
MemTotal: h.MemTotal,
|
|
||||||
DiskTotal: h.DiskTotal,
|
|
||||||
SwapTotal: h.SwapTotal,
|
|
||||||
Arch: h.Arch,
|
|
||||||
Virtualization: h.Virtualization,
|
|
||||||
BootTime: h.BootTime,
|
|
||||||
Ip: h.IP,
|
|
||||||
CountryCode: h.CountryCode,
|
|
||||||
Version: h.Version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PB2Host ...
|
|
||||||
func PB2Host(h *pb.Host) Host {
|
|
||||||
|
|
||||||
cpuCount := make(map[string]int, 0)
|
|
||||||
cpus := h.GetCpu()
|
|
||||||
for _, u := range cpus {
|
|
||||||
cpuCount[u]++
|
|
||||||
}
|
|
||||||
|
|
||||||
var distCpu []string
|
|
||||||
for u, num := range cpuCount {
|
|
||||||
distCpu = append(distCpu, fmt.Sprintf("%sx%d", u, num))
|
|
||||||
}
|
|
||||||
|
|
||||||
return Host{
|
|
||||||
Platform: h.GetPlatform(),
|
|
||||||
PlatformVersion: h.GetPlatformVersion(),
|
|
||||||
CPU: distCpu,
|
|
||||||
MemTotal: h.GetMemTotal(),
|
|
||||||
DiskTotal: h.GetDiskTotal(),
|
|
||||||
SwapTotal: h.GetSwapTotal(),
|
|
||||||
Arch: h.GetArch(),
|
|
||||||
Virtualization: h.GetVirtualization(),
|
|
||||||
BootTime: h.GetBootTime(),
|
|
||||||
IP: h.GetIp(),
|
|
||||||
CountryCode: h.GetCountryCode(),
|
|
||||||
Version: h.GetVersion(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
model/monitor_history.go
Normal file
22
model/monitor_history.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
pb "github.com/naiba/nezha/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MonitorHistory struct {
|
||||||
|
Common
|
||||||
|
MonitorID uint64
|
||||||
|
Delay float32 // 延迟,毫秒
|
||||||
|
Data string
|
||||||
|
Successful bool // 是否成功
|
||||||
|
}
|
||||||
|
|
||||||
|
func PB2MonitorHistory(r *pb.TaskResult) MonitorHistory {
|
||||||
|
return MonitorHistory{
|
||||||
|
Delay: r.GetDelay(),
|
||||||
|
Successful: r.GetSuccessful(),
|
||||||
|
MonitorID: r.GetId(),
|
||||||
|
Data: r.GetData(),
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ import (
|
|||||||
pb "github.com/naiba/nezha/proto"
|
pb "github.com/naiba/nezha/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server ..
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Common
|
Common
|
||||||
Name string
|
Name string
|
||||||
@ -16,11 +15,11 @@ type Server struct {
|
|||||||
Secret string `json:"-"`
|
Secret string `json:"-"`
|
||||||
Tag string
|
Tag string
|
||||||
Host *Host `gorm:"-"`
|
Host *Host `gorm:"-"`
|
||||||
State *State `gorm:"-"`
|
State *HostState `gorm:"-"`
|
||||||
LastActive time.Time
|
LastActive time.Time
|
||||||
|
|
||||||
Stream pb.NezhaService_HeartbeatServer `gorm:"-" json:"-"`
|
TaskClose chan error `gorm:"-" json:"-"`
|
||||||
StreamClose chan<- error `gorm:"-" json:"-"`
|
TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Server) Marshal() template.JS {
|
func (s Server) Marshal() template.JS {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/naiba/com"
|
"github.com/naiba/com"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User ...
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Common
|
Common
|
||||||
Login string `gorm:"UNIQUE_INDEX" json:"login,omitempty"` // 登录名
|
Login string `gorm:"UNIQUE_INDEX" json:"login,omitempty"` // 登录名
|
||||||
@ -26,7 +25,6 @@ type User struct {
|
|||||||
TeamsID []uint64 `gorm:"-"`
|
TeamsID []uint64 `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUserFromGitHub ..
|
|
||||||
func NewUserFromGitHub(gu *github.User) User {
|
func NewUserFromGitHub(gu *github.User) User {
|
||||||
var u User
|
var u User
|
||||||
u.ID = uint64(gu.GetID())
|
u.ID = uint64(gu.GetID())
|
||||||
@ -45,7 +43,6 @@ func NewUserFromGitHub(gu *github.User) User {
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueNewToken ...
|
|
||||||
func (u *User) IssueNewToken() {
|
func (u *User) IssueNewToken() {
|
||||||
u.Token = com.MD5(fmt.Sprintf("%d%d%s", time.Now().UnixNano(), u.ID, u.Login))
|
u.Token = com.MD5(fmt.Sprintf("%d%d%s", time.Now().UnixNano(), u.ID, u.Login))
|
||||||
u.TokenExpired = time.Now().AddDate(0, 2, 0)
|
u.TokenExpired = time.Now().AddDate(0, 2, 0)
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/naiba/nezha/service/dao"
|
"github.com/naiba/nezha/service/dao"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthorizeOption ..
|
|
||||||
type AuthorizeOption struct {
|
type AuthorizeOption struct {
|
||||||
Guest bool
|
Guest bool
|
||||||
Member bool
|
Member bool
|
||||||
@ -21,7 +20,6 @@ type AuthorizeOption struct {
|
|||||||
Btn string
|
Btn string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorize ..
|
|
||||||
func Authorize(opt AuthorizeOption) func(*gin.Context) {
|
func Authorize(opt AuthorizeOption) func(*gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
token, err := c.Cookie(dao.Conf.Site.CookieName)
|
token, err := c.Cookie(dao.Conf.Site.CookieName)
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/naiba/nezha/model"
|
"github.com/naiba/nezha/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrInfo ..
|
|
||||||
type ErrInfo struct {
|
type ErrInfo struct {
|
||||||
Code uint64
|
Code uint64
|
||||||
Title string
|
Title string
|
||||||
@ -17,7 +16,6 @@ type ErrInfo struct {
|
|||||||
Btn string
|
Btn string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowErrorPage ..
|
|
||||||
func ShowErrorPage(c *gin.Context, i ErrInfo, isPage bool) {
|
func ShowErrorPage(c *gin.Context, i ErrInfo, isPage bool) {
|
||||||
if isPage {
|
if isPage {
|
||||||
c.HTML(http.StatusOK, "dashboard/error", CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, "dashboard/error", CommonEnvironment(c, gin.H{
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/naiba/nezha/service/dao"
|
"github.com/naiba/nezha/service/dao"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommonEnvironment ..
|
|
||||||
func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
||||||
data["MatchedPath"] = c.MustGet("MatchedPath")
|
data["MatchedPath"] = c.MustGet("MatchedPath")
|
||||||
data["Version"] = dao.Version
|
data["Version"] = dao.Version
|
||||||
@ -27,7 +26,6 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordPath ..
|
|
||||||
func RecordPath(c *gin.Context) {
|
func RecordPath(c *gin.Context) {
|
||||||
url := c.Request.URL.String()
|
url := c.Request.URL.String()
|
||||||
for _, p := range c.Params {
|
for _, p := range c.Params {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.25.0
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v3.13.0
|
// protoc v3.14.0
|
||||||
// source: proto/nezha.proto
|
// source: proto/nezha.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@ -275,6 +275,148 @@ func (x *State) GetUptime() uint64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Task struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
|
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Task) Reset() {
|
||||||
|
*x = Task{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Task) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Task) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Task) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Task) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Task) GetId() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Task) GetType() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Task) GetData() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Data
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type TaskResult struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
|
Delay float32 `protobuf:"fixed32,3,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||||
|
Data string `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
|
Successful bool `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) Reset() {
|
||||||
|
*x = TaskResult{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*TaskResult) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *TaskResult) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_nezha_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
|
||||||
|
func (*TaskResult) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) GetId() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) GetType() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) GetDelay() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Delay
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) GetData() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Data
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResult) GetSuccessful() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Successful
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type Receipt struct {
|
type Receipt struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -286,7 +428,7 @@ type Receipt struct {
|
|||||||
func (x *Receipt) Reset() {
|
func (x *Receipt) Reset() {
|
||||||
*x = Receipt{}
|
*x = Receipt{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -299,7 +441,7 @@ func (x *Receipt) String() string {
|
|||||||
func (*Receipt) ProtoMessage() {}
|
func (*Receipt) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Receipt) ProtoReflect() protoreflect.Message {
|
func (x *Receipt) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_nezha_proto_msgTypes[2]
|
mi := &file_proto_nezha_proto_msgTypes[4]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -312,7 +454,7 @@ func (x *Receipt) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Receipt.ProtoReflect.Descriptor instead.
|
||||||
func (*Receipt) Descriptor() ([]byte, []int) {
|
func (*Receipt) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_nezha_proto_rawDescGZIP(), []int{2}
|
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Receipt) GetProced() bool {
|
func (x *Receipt) GetProced() bool {
|
||||||
@ -322,108 +464,6 @@ func (x *Receipt) GetProced() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type Beat struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Timestamp string `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Beat) Reset() {
|
|
||||||
*x = Beat{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Beat) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Beat) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Beat) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proto_nezha_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Beat.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Beat) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proto_nezha_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Beat) GetTimestamp() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Timestamp
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type Command struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Type uint64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"`
|
|
||||||
Data string `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Command) Reset() {
|
|
||||||
*x = Command{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Command) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Command) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Command) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proto_nezha_proto_msgTypes[4]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Command.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Command) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proto_nezha_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Command) GetType() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Type
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Command) GetData() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Data
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proto_nezha_proto protoreflect.FileDescriptor
|
var File_proto_nezha_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proto_nezha_proto_rawDesc = []byte{
|
var file_proto_nezha_proto_rawDesc = []byte{
|
||||||
@ -468,25 +508,36 @@ var file_proto_nezha_proto_rawDesc = []byte{
|
|||||||
0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70,
|
0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70,
|
||||||
0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75,
|
0x65, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75,
|
||||||
0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
|
0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
|
||||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x21,
|
0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x3e,
|
||||||
0x0a, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f,
|
0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65,
|
0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
|
||||||
0x64, 0x22, 0x24, 0x0a, 0x04, 0x42, 0x65, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
|
0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
|
||||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69,
|
0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7a,
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x31, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
|
0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
||||||
0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02,
|
0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x96, 0x01, 0x0a, 0x0c, 0x4e,
|
0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52,
|
||||||
0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x09, 0x48,
|
0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
|
||||||
0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x75,
|
||||||
0x2e, 0x42, 0x65, 0x61, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f,
|
0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x0b, 0x52, 0x65, 0x70,
|
0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x21, 0x0a, 0x07, 0x52, 0x65,
|
||||||
0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x18,
|
||||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
|
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x32, 0xd6, 0x01,
|
||||||
0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69,
|
0x0a, 0x0c, 0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33,
|
||||||
0x73, 0x74, 0x65, 0x72, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73,
|
0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x74,
|
||||||
0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74,
|
||||||
0x74, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
||||||
|
0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73,
|
||||||
|
0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||||
|
0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63,
|
||||||
|
0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74,
|
||||||
|
0x54, 0x61, 0x73, 0x6b, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73,
|
||||||
|
0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||||
|
0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x0b, 0x52, 0x65, 0x71,
|
||||||
|
0x75, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61,
|
||||||
|
0x73, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -505,19 +556,21 @@ var file_proto_nezha_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
|||||||
var file_proto_nezha_proto_goTypes = []interface{}{
|
var file_proto_nezha_proto_goTypes = []interface{}{
|
||||||
(*Host)(nil), // 0: proto.Host
|
(*Host)(nil), // 0: proto.Host
|
||||||
(*State)(nil), // 1: proto.State
|
(*State)(nil), // 1: proto.State
|
||||||
(*Receipt)(nil), // 2: proto.Receipt
|
(*Task)(nil), // 2: proto.Task
|
||||||
(*Beat)(nil), // 3: proto.Beat
|
(*TaskResult)(nil), // 3: proto.TaskResult
|
||||||
(*Command)(nil), // 4: proto.Command
|
(*Receipt)(nil), // 4: proto.Receipt
|
||||||
}
|
}
|
||||||
var file_proto_nezha_proto_depIdxs = []int32{
|
var file_proto_nezha_proto_depIdxs = []int32{
|
||||||
3, // 0: proto.NezhaService.Heartbeat:input_type -> proto.Beat
|
1, // 0: proto.NezhaService.ReportSystemState:input_type -> proto.State
|
||||||
1, // 1: proto.NezhaService.ReportState:input_type -> proto.State
|
0, // 1: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host
|
||||||
0, // 2: proto.NezhaService.Register:input_type -> proto.Host
|
3, // 2: proto.NezhaService.ReportTask:input_type -> proto.TaskResult
|
||||||
4, // 3: proto.NezhaService.Heartbeat:output_type -> proto.Command
|
0, // 3: proto.NezhaService.RequestTask:input_type -> proto.Host
|
||||||
2, // 4: proto.NezhaService.ReportState:output_type -> proto.Receipt
|
4, // 4: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt
|
||||||
2, // 5: proto.NezhaService.Register:output_type -> proto.Receipt
|
4, // 5: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt
|
||||||
3, // [3:6] is the sub-list for method output_type
|
4, // 6: proto.NezhaService.ReportTask:output_type -> proto.Receipt
|
||||||
0, // [0:3] is the sub-list for method input_type
|
2, // 7: proto.NezhaService.RequestTask:output_type -> proto.Task
|
||||||
|
4, // [4:8] is the sub-list for method output_type
|
||||||
|
0, // [0:4] is the sub-list for method input_type
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
0, // [0:0] is the sub-list for field type_name
|
0, // [0:0] is the sub-list for field type_name
|
||||||
@ -554,7 +607,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
file_proto_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Receipt); i {
|
switch v := v.(*Task); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@ -566,7 +619,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
file_proto_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Beat); i {
|
switch v := v.(*TaskResult); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@ -578,7 +631,7 @@ func file_proto_nezha_proto_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proto_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
file_proto_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Command); i {
|
switch v := v.(*Receipt); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
case 1:
|
||||||
@ -622,9 +675,10 @@ const _ = grpc.SupportPackageIsVersion6
|
|||||||
//
|
//
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||||
type NezhaServiceClient interface {
|
type NezhaServiceClient interface {
|
||||||
Heartbeat(ctx context.Context, in *Beat, opts ...grpc.CallOption) (NezhaService_HeartbeatClient, error)
|
ReportSystemState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error)
|
||||||
ReportState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error)
|
ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
||||||
Register(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error)
|
ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error)
|
||||||
|
RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type nezhaServiceClient struct {
|
type nezhaServiceClient struct {
|
||||||
@ -635,12 +689,39 @@ func NewNezhaServiceClient(cc grpc.ClientConnInterface) NezhaServiceClient {
|
|||||||
return &nezhaServiceClient{cc}
|
return &nezhaServiceClient{cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nezhaServiceClient) Heartbeat(ctx context.Context, in *Beat, opts ...grpc.CallOption) (NezhaService_HeartbeatClient, error) {
|
func (c *nezhaServiceClient) ReportSystemState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error) {
|
||||||
stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[0], "/proto.NezhaService/Heartbeat", opts...)
|
out := new(Receipt)
|
||||||
|
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemState", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
x := &nezhaServiceHeartbeatClient{stream}
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nezhaServiceClient) ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) {
|
||||||
|
out := new(Receipt)
|
||||||
|
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemInfo", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nezhaServiceClient) ReportTask(ctx context.Context, in *TaskResult, opts ...grpc.CallOption) (*Receipt, error) {
|
||||||
|
out := new(Receipt)
|
||||||
|
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportTask", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nezhaServiceClient) RequestTask(ctx context.Context, in *Host, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[0], "/proto.NezhaService/RequestTask", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &nezhaServiceRequestTaskClient{stream}
|
||||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -650,140 +731,148 @@ func (c *nezhaServiceClient) Heartbeat(ctx context.Context, in *Beat, opts ...gr
|
|||||||
return x, nil
|
return x, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type NezhaService_HeartbeatClient interface {
|
type NezhaService_RequestTaskClient interface {
|
||||||
Recv() (*Command, error)
|
Recv() (*Task, error)
|
||||||
grpc.ClientStream
|
grpc.ClientStream
|
||||||
}
|
}
|
||||||
|
|
||||||
type nezhaServiceHeartbeatClient struct {
|
type nezhaServiceRequestTaskClient struct {
|
||||||
grpc.ClientStream
|
grpc.ClientStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *nezhaServiceHeartbeatClient) Recv() (*Command, error) {
|
func (x *nezhaServiceRequestTaskClient) Recv() (*Task, error) {
|
||||||
m := new(Command)
|
m := new(Task)
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *nezhaServiceClient) ReportState(ctx context.Context, in *State, opts ...grpc.CallOption) (*Receipt, error) {
|
|
||||||
out := new(Receipt)
|
|
||||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportState", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *nezhaServiceClient) Register(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) {
|
|
||||||
out := new(Receipt)
|
|
||||||
err := c.cc.Invoke(ctx, "/proto.NezhaService/Register", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NezhaServiceServer is the server API for NezhaService service.
|
// NezhaServiceServer is the server API for NezhaService service.
|
||||||
type NezhaServiceServer interface {
|
type NezhaServiceServer interface {
|
||||||
Heartbeat(*Beat, NezhaService_HeartbeatServer) error
|
ReportSystemState(context.Context, *State) (*Receipt, error)
|
||||||
ReportState(context.Context, *State) (*Receipt, error)
|
ReportSystemInfo(context.Context, *Host) (*Receipt, error)
|
||||||
Register(context.Context, *Host) (*Receipt, error)
|
ReportTask(context.Context, *TaskResult) (*Receipt, error)
|
||||||
|
RequestTask(*Host, NezhaService_RequestTaskServer) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedNezhaServiceServer can be embedded to have forward compatible implementations.
|
// UnimplementedNezhaServiceServer can be embedded to have forward compatible implementations.
|
||||||
type UnimplementedNezhaServiceServer struct {
|
type UnimplementedNezhaServiceServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*UnimplementedNezhaServiceServer) Heartbeat(*Beat, NezhaService_HeartbeatServer) error {
|
func (*UnimplementedNezhaServiceServer) ReportSystemState(context.Context, *State) (*Receipt, error) {
|
||||||
return status.Errorf(codes.Unimplemented, "method Heartbeat not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ReportSystemState not implemented")
|
||||||
}
|
}
|
||||||
func (*UnimplementedNezhaServiceServer) ReportState(context.Context, *State) (*Receipt, error) {
|
func (*UnimplementedNezhaServiceServer) ReportSystemInfo(context.Context, *Host) (*Receipt, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ReportState not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ReportSystemInfo not implemented")
|
||||||
}
|
}
|
||||||
func (*UnimplementedNezhaServiceServer) Register(context.Context, *Host) (*Receipt, error) {
|
func (*UnimplementedNezhaServiceServer) ReportTask(context.Context, *TaskResult) (*Receipt, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method Register not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ReportTask not implemented")
|
||||||
|
}
|
||||||
|
func (*UnimplementedNezhaServiceServer) RequestTask(*Host, NezhaService_RequestTaskServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method RequestTask not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterNezhaServiceServer(s *grpc.Server, srv NezhaServiceServer) {
|
func RegisterNezhaServiceServer(s *grpc.Server, srv NezhaServiceServer) {
|
||||||
s.RegisterService(&_NezhaService_serviceDesc, srv)
|
s.RegisterService(&_NezhaService_serviceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _NezhaService_Heartbeat_Handler(srv interface{}, stream grpc.ServerStream) error {
|
func _NezhaService_ReportSystemState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
m := new(Beat)
|
|
||||||
if err := stream.RecvMsg(m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return srv.(NezhaServiceServer).Heartbeat(m, &nezhaServiceHeartbeatServer{stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type NezhaService_HeartbeatServer interface {
|
|
||||||
Send(*Command) error
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type nezhaServiceHeartbeatServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *nezhaServiceHeartbeatServer) Send(m *Command) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NezhaService_ReportState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(State)
|
in := new(State)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(NezhaServiceServer).ReportState(ctx, in)
|
return srv.(NezhaServiceServer).ReportSystemState(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/proto.NezhaService/ReportState",
|
FullMethod: "/proto.NezhaService/ReportSystemState",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(NezhaServiceServer).ReportState(ctx, req.(*State))
|
return srv.(NezhaServiceServer).ReportSystemState(ctx, req.(*State))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _NezhaService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _NezhaService_ReportSystemInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(Host)
|
in := new(Host)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if interceptor == nil {
|
if interceptor == nil {
|
||||||
return srv.(NezhaServiceServer).Register(ctx, in)
|
return srv.(NezhaServiceServer).ReportSystemInfo(ctx, in)
|
||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/proto.NezhaService/Register",
|
FullMethod: "/proto.NezhaService/ReportSystemInfo",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(NezhaServiceServer).Register(ctx, req.(*Host))
|
return srv.(NezhaServiceServer).ReportSystemInfo(ctx, req.(*Host))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _NezhaService_ReportTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TaskResult)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(NezhaServiceServer).ReportTask(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/proto.NezhaService/ReportTask",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(NezhaServiceServer).ReportTask(ctx, req.(*TaskResult))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _NezhaService_RequestTask_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
m := new(Host)
|
||||||
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return srv.(NezhaServiceServer).RequestTask(m, &nezhaServiceRequestTaskServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type NezhaService_RequestTaskServer interface {
|
||||||
|
Send(*Task) error
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nezhaServiceRequestTaskServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nezhaServiceRequestTaskServer) Send(m *Task) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
var _NezhaService_serviceDesc = grpc.ServiceDesc{
|
var _NezhaService_serviceDesc = grpc.ServiceDesc{
|
||||||
ServiceName: "proto.NezhaService",
|
ServiceName: "proto.NezhaService",
|
||||||
HandlerType: (*NezhaServiceServer)(nil),
|
HandlerType: (*NezhaServiceServer)(nil),
|
||||||
Methods: []grpc.MethodDesc{
|
Methods: []grpc.MethodDesc{
|
||||||
{
|
{
|
||||||
MethodName: "ReportState",
|
MethodName: "ReportSystemState",
|
||||||
Handler: _NezhaService_ReportState_Handler,
|
Handler: _NezhaService_ReportSystemState_Handler,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MethodName: "Register",
|
MethodName: "ReportSystemInfo",
|
||||||
Handler: _NezhaService_Register_Handler,
|
Handler: _NezhaService_ReportSystemInfo_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "ReportTask",
|
||||||
|
Handler: _NezhaService_ReportTask_Handler,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{
|
||||||
{
|
{
|
||||||
StreamName: "Heartbeat",
|
StreamName: "RequestTask",
|
||||||
Handler: _NezhaService_Heartbeat_Handler,
|
Handler: _NezhaService_RequestTask_Handler,
|
||||||
ServerStreams: true,
|
ServerStreams: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
option go_package = "proto";
|
||||||
|
|
||||||
package proto;
|
package proto;
|
||||||
|
|
||||||
service NezhaService {
|
service NezhaService {
|
||||||
rpc Heartbeat(Beat)returns(stream Command){}
|
rpc ReportSystemState(State)returns(Receipt){}
|
||||||
rpc ReportState(State)returns(Receipt){}
|
rpc ReportSystemInfo(Host)returns(Receipt){}
|
||||||
rpc Register(Host)returns(Receipt){}
|
rpc ReportTask(TaskResult)returns(Receipt){}
|
||||||
|
rpc RequestTask(Host)returns(stream Task){}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Host {
|
message Host {
|
||||||
@ -35,15 +37,20 @@ message State {
|
|||||||
uint64 uptime = 10;
|
uint64 uptime = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Task {
|
||||||
|
uint64 id = 1;
|
||||||
|
uint64 type = 2;
|
||||||
|
string data = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TaskResult {
|
||||||
|
uint64 id = 1;
|
||||||
|
uint64 type = 2;
|
||||||
|
float delay = 3;
|
||||||
|
string data = 4;
|
||||||
|
bool successful = 5;
|
||||||
|
}
|
||||||
|
|
||||||
message Receipt{
|
message Receipt{
|
||||||
bool proced = 1;
|
bool proced = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Beat {
|
|
||||||
string timestamp = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Command {
|
|
||||||
uint64 type = 1;
|
|
||||||
string data = 2;
|
|
||||||
}
|
|
||||||
|
@ -77,3 +77,56 @@
|
|||||||
color: rgba(255, 255, 255, .7);
|
color: rgba(255, 255, 255, .7);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.service-status .round>i {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
border-radius: .5rem;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: .3rem;
|
||||||
|
background-color: slategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .danger.button {
|
||||||
|
background-color: crimson;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .good.button {
|
||||||
|
background-color: rgb(0, 235, 139);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .warning.button {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .danger>i {
|
||||||
|
background-color: crimson;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .good>i {
|
||||||
|
background-color: rgb(0, 235, 139);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .warning>i {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .three.column p {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .three.column p:last-child {
|
||||||
|
float: right;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .eleven.column {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status .eleven.column>.ui.button {
|
||||||
|
width: 8px !important;
|
||||||
|
padding: unset !important;
|
||||||
|
margin-top: unset !important;
|
||||||
|
margin-bottom: unset !important;
|
||||||
|
}
|
@ -39,7 +39,7 @@ function showFormModal(modelSelector, formID, URL, getData) {
|
|||||||
obj[item.name] = (item.name.endsWith('_id') ||
|
obj[item.name] = (item.name.endsWith('_id') ||
|
||||||
item.name === 'id' || item.name === 'ID' ||
|
item.name === 'id' || item.name === 'ID' ||
|
||||||
item.name === 'RequestType' || item.name === 'RequestMethod' ||
|
item.name === 'RequestType' || item.name === 'RequestMethod' ||
|
||||||
item.name === 'DisplayIndex') ? parseInt(item.value) : item.value;
|
item.name === 'DisplayIndex' || item.name === 'Type') ? parseInt(item.value) : item.value;
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
$.post(URL, JSON.stringify(data)).done(function (resp) {
|
$.post(URL, JSON.stringify(data)).done(function (resp) {
|
||||||
@ -118,6 +118,17 @@ function addOrEditServer(server) {
|
|||||||
showFormModal('.server.modal', '#serverForm', '/api/server')
|
showFormModal('.server.modal', '#serverForm', '/api/server')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addOrEditMonitor(monitor) {
|
||||||
|
const modal = $('.monitor.modal')
|
||||||
|
modal.children('.header').text((monitor ? '修改' : '添加') + '监控')
|
||||||
|
modal.find('.positive.button').html(monitor ? '修改<i class="edit icon"></i>' : '添加<i class="add icon"></i>')
|
||||||
|
modal.find('input[name=ID]').val(monitor ? monitor.ID : null)
|
||||||
|
modal.find('input[name=Name]').val(monitor ? monitor.Name : null)
|
||||||
|
modal.find('input[name=Target]').val(monitor ? monitor.Target : null)
|
||||||
|
modal.find('select[name=Type]').val(monitor ? monitor.Type : 1)
|
||||||
|
showFormModal('.monitor.modal', '#monitorForm', '/api/monitor')
|
||||||
|
}
|
||||||
|
|
||||||
function deleteRequest(api) {
|
function deleteRequest(api) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: api,
|
url: api,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
{{define "common/footer"}}
|
{{define "common/footer"}}
|
||||||
<div class="ui inverted vertical footer segment">
|
<div class="ui inverted vertical footer segment">
|
||||||
<div class="ui center aligned is-size-7 container">
|
<div class="ui center aligned is-size-7 container">
|
||||||
Powered by <a href="https://github.com/naiba/nezha" style="color: white;" target="_blank">哪吒面板</a> build ·
|
Powered by <a href="https://github.com/naiba/nezha" style="color: white;" target="_blank">哪吒面板</a> {{.Version}}
|
||||||
{{.Version}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.css">
|
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/main.css?v202012252026">
|
<link rel="stylesheet" type="text/css" href="/static/main.css?v202101160044">
|
||||||
<link rel="shortcut icon" type="image/png" href="/static/logo.png" />
|
<link rel="shortcut icon" type="image/png" href="/static/logo.png" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -5,13 +5,14 @@
|
|||||||
<img src="/static/logo.png">
|
<img src="/static/logo.png">
|
||||||
</div>
|
</div>
|
||||||
<a class="item{{if eq .MatchedPath " /"}} active{{end}}" href="/">首页</a>
|
<a class="item{{if eq .MatchedPath " /"}} active{{end}}" href="/">首页</a>
|
||||||
|
<a class="item{{if eq .MatchedPath " /service"}} active{{end}}" href="/service">服务状态</a>
|
||||||
{{if .Admin}}
|
{{if .Admin}}
|
||||||
<a class="item{{if eq .MatchedPath " /server"}} active{{end}}" href="/server">服务器</a>
|
<a class="item{{if eq .MatchedPath " /server"}} active{{end}}" href="/server">服务器</a>
|
||||||
|
<a class="item{{if eq .MatchedPath " /monitor"}} active{{end}}" href="/monitor">监控</a>
|
||||||
<a class="item{{if eq .MatchedPath " /notification"}} active{{end}}" href="/notification">通知</a>
|
<a class="item{{if eq .MatchedPath " /notification"}} active{{end}}" href="/notification">通知</a>
|
||||||
<a class="item{{if eq .MatchedPath " /setting"}} active{{end}}" href="/setting">设置</a>
|
<a class="item{{if eq .MatchedPath " /setting"}} active{{end}}" href="/setting">设置</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="right menu">
|
<div class="right menu">
|
||||||
<a class="item" href="https://github.com/naiba/nezha/issues" target="_blank">反馈</a>
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
{{if .Admin}}
|
{{if .Admin}}
|
||||||
<div class="ui simple dropdown">
|
<div class="ui simple dropdown">
|
||||||
|
31
resource/template/component/monitor.html
Normal file
31
resource/template/component/monitor.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{{define "component/monitor"}}
|
||||||
|
<div class="ui tiny monitor modal transition hidden">
|
||||||
|
<div class="header">添加监控</div>
|
||||||
|
<div class="content">
|
||||||
|
<form id="monitorForm" class="ui form">
|
||||||
|
<input type="hidden" name="ID">
|
||||||
|
<div class="field">
|
||||||
|
<label>备注</label>
|
||||||
|
<input type="text" name="Name" placeholder="博客">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>目标</label>
|
||||||
|
<input type="text" name="Target" placeholder="https://t.tt,t.tt,t.tt:80">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>类型</label>
|
||||||
|
<select name="Type" class="ui fluid dropdown">
|
||||||
|
<option value="1">HTTP-GET</option>
|
||||||
|
<option value="2">ICMP-Ping</option>
|
||||||
|
<option value="3">TCP-Ping</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class=" actions">
|
||||||
|
<div class="ui negative button">取消</div>
|
||||||
|
<button class="ui positive right labeled icon button">确认<i class="checkmark icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
49
resource/template/dashboard/monitor.html
Normal file
49
resource/template/dashboard/monitor.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{{define "dashboard/monitor"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{template "common/menu" .}}
|
||||||
|
<div class="nb-container">
|
||||||
|
<div class="ui container">
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="right floated right aligned twelve wide column">
|
||||||
|
<button class="ui right labeled positive icon button" onclick="addOrEditMonitor()"><i
|
||||||
|
class="add icon"></i> 添加监控
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="ui very basic table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th>类型</th>
|
||||||
|
<th>目标</th>
|
||||||
|
<th>管理</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $monitor := .Monitors}}
|
||||||
|
<tr>
|
||||||
|
<td>{{$monitor.ID}}</td>
|
||||||
|
<td>{{$monitor.Name}}</td>
|
||||||
|
<td>{{$monitor.Target}}</td>
|
||||||
|
<td>{{$monitor.Type}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui mini icon buttons">
|
||||||
|
<button class="ui button" onclick="addOrEditMonitor({{$monitor}})">
|
||||||
|
<i class="edit icon"></i>
|
||||||
|
</button>
|
||||||
|
<button class="ui button"
|
||||||
|
onclick="showConfirm('删除监控','确认删除此监控?',deleteRequest,'/api/monitor/'+{{$monitor.ID}})">
|
||||||
|
<i class="delete icon"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "component/monitor"}}
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
{{end}}
|
@ -14,8 +14,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<select name="Theme">
|
<select name="Theme">
|
||||||
<option value="default">默认主题</option>
|
<option value="default"{{if eq .Conf.Site.Theme "default"}} selected="selected"{{end}}>默认主题</option>
|
||||||
<option value="hotaru">CakeMine-Hotaru</option>
|
<option value="hotaru"{{if eq .Conf.Site.Theme "hotaru"}} selected="selected"{{end}}>CokeMine Hotaru</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
42
resource/template/theme-default/service.html
Normal file
42
resource/template/theme-default/service.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{define "theme-default/service"}}
|
||||||
|
{{template "common/header" .}}
|
||||||
|
{{template "common/menu" .}}
|
||||||
|
<div class="nb-container">
|
||||||
|
<div class="ui container">
|
||||||
|
<div class="ui segment service-status">
|
||||||
|
{{range $service := .Services}}
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="three wide column">
|
||||||
|
<p>{{$service.Monitor.Name}}</p>
|
||||||
|
<p>30天在线率{{divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)}}%</p>
|
||||||
|
</div>
|
||||||
|
<div class="eleven wide column">
|
||||||
|
{{range $i,$d := $service.Delay}}
|
||||||
|
<div class="ui icon button{{if gt (add (index $service.Up $i) (index $service.Down $i)) 0}}
|
||||||
|
{{if gt (div (index $service.Down $i) (add (index $service.Up $i) (index $service.Down $i))) 30.0}}danger
|
||||||
|
{{else if gt (div (index $service.Down $i) (add (index $service.Up $i) (index $service.Down $i))) 10.0}}
|
||||||
|
warning{{else}}good{{end}}
|
||||||
|
{{end}}" data-tooltip="{{dayBefore $i}},平均延迟:{{$d}}ms">
|
||||||
|
<i class="delay"></i>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="two wide column round{{if gt (addU64 $service.TotalUp $service.TotalDown) 0}}
|
||||||
|
{{if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 30.0}}danger{{else if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 10.0}}warning{{else}}good{{end}}
|
||||||
|
{{end}}">
|
||||||
|
<i></i>
|
||||||
|
{{if gt (addU64 $service.TotalUp $service.TotalDown) 0}}
|
||||||
|
{{if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 30.0}}故障
|
||||||
|
{{else if gt (divU64 $service.TotalDown (addU64 $service.TotalUp $service.TotalDown)) 10.0}}
|
||||||
|
低可用{{else}}良好{{end}}
|
||||||
|
{{else}}无数据
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "common/footer" .}}
|
||||||
|
{{end}}
|
@ -8,7 +8,6 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
"github.com/naiba/nezha/model"
|
||||||
pb "github.com/naiba/nezha/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -16,30 +15,18 @@ const (
|
|||||||
ReportDelay = 2
|
ReportDelay = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conf ..
|
|
||||||
var Conf *model.Config
|
var Conf *model.Config
|
||||||
|
|
||||||
// Cache ..
|
|
||||||
var Cache *cache.Cache
|
var Cache *cache.Cache
|
||||||
|
|
||||||
// DB ..
|
|
||||||
var DB *gorm.DB
|
var DB *gorm.DB
|
||||||
|
|
||||||
// ServerList ..
|
|
||||||
var ServerList map[uint64]*model.Server
|
var ServerList map[uint64]*model.Server
|
||||||
var SortedServerList []*model.Server
|
var SortedServerList []*model.Server
|
||||||
|
|
||||||
// ServerLock ..
|
|
||||||
var ServerLock sync.RWMutex
|
var ServerLock sync.RWMutex
|
||||||
|
|
||||||
// Version ..
|
var Version = "v0.2.0"
|
||||||
var Version = "debug"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if len(Version) > 7 {
|
|
||||||
Version = Version[:7]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReSortServer() {
|
func ReSortServer() {
|
||||||
SortedServerList = []*model.Server{}
|
SortedServerList = []*model.Server{}
|
||||||
@ -51,19 +38,3 @@ func ReSortServer() {
|
|||||||
return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex
|
return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendCommand ..
|
|
||||||
func SendCommand(cmd *pb.Command) {
|
|
||||||
ServerLock.RLock()
|
|
||||||
defer ServerLock.RUnlock()
|
|
||||||
var err error
|
|
||||||
for _, server := range ServerList {
|
|
||||||
if server.Stream != nil {
|
|
||||||
err = server.Stream.Send(cmd)
|
|
||||||
if err != nil {
|
|
||||||
close(server.StreamClose)
|
|
||||||
server.Stream = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -26,7 +26,6 @@ type ipDotSbGeoIP struct {
|
|||||||
|
|
||||||
var netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdate uint64
|
var netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdate uint64
|
||||||
|
|
||||||
// GetHost ..
|
|
||||||
func GetHost() *model.Host {
|
func GetHost() *model.Host {
|
||||||
hi, _ := host.Info()
|
hi, _ := host.Info()
|
||||||
var cpus []string
|
var cpus []string
|
||||||
@ -60,8 +59,7 @@ func GetHost() *model.Host {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetState ..
|
func GetState(delay int64) *model.HostState {
|
||||||
func GetState(delay int64) *model.State {
|
|
||||||
hi, _ := host.Info()
|
hi, _ := host.Info()
|
||||||
// Memory
|
// Memory
|
||||||
mv, _ := mem.VirtualMemory()
|
mv, _ := mem.VirtualMemory()
|
||||||
@ -75,7 +73,7 @@ func GetState(delay int64) *model.State {
|
|||||||
// Disk
|
// Disk
|
||||||
u, _ := disk.Usage("/")
|
u, _ := disk.Usage("/")
|
||||||
|
|
||||||
return &model.State{
|
return &model.HostState{
|
||||||
CPU: cpuPercent,
|
CPU: cpuPercent,
|
||||||
MemUsed: mv.Used,
|
MemUsed: mv.Used,
|
||||||
SwapUsed: ms.Used,
|
SwapUsed: ms.Used,
|
||||||
@ -88,7 +86,6 @@ func GetState(delay int64) *model.State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackNetworkSpeed ..
|
|
||||||
func TrackNetworkSpeed() {
|
func TrackNetworkSpeed() {
|
||||||
var innerNetInTransfer, innerNetOutTransfer uint64
|
var innerNetInTransfer, innerNetOutTransfer uint64
|
||||||
nc, err := net.IOCounters(false)
|
nc, err := net.IOCounters(false)
|
||||||
|
@ -10,23 +10,19 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthHandler ..
|
|
||||||
type AuthHandler struct {
|
type AuthHandler struct {
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret string
|
ClientSecret string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRequestMetadata ..
|
|
||||||
func (a *AuthHandler) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
func (a *AuthHandler) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
return map[string]string{"client_id": a.ClientID, "client_secret": a.ClientSecret}, nil
|
return map[string]string{"client_id": a.ClientID, "client_secret": a.ClientSecret}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequireTransportSecurity ..
|
|
||||||
func (a *AuthHandler) RequireTransportSecurity() bool {
|
func (a *AuthHandler) RequireTransportSecurity() bool {
|
||||||
return !dao.Conf.Debug
|
return !dao.Conf.Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ..
|
|
||||||
func (a *AuthHandler) Check(ctx context.Context) (clientID uint64, err error) {
|
func (a *AuthHandler) Check(ctx context.Context) (clientID uint64, err error) {
|
||||||
md, ok := metadata.FromIncomingContext(ctx)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -3,7 +3,6 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
"github.com/naiba/nezha/model"
|
||||||
@ -12,13 +11,60 @@ import (
|
|||||||
"github.com/naiba/nezha/service/dao"
|
"github.com/naiba/nezha/service/dao"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NezhaHandler ..
|
|
||||||
type NezhaHandler struct {
|
type NezhaHandler struct {
|
||||||
Auth *AuthHandler
|
Auth *AuthHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportState ..
|
func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Receipt, error) {
|
||||||
func (s *NezhaHandler) ReportState(c context.Context, r *pb.State) (*pb.Receipt, error) {
|
var err error
|
||||||
|
if _, err = s.Auth.Check(c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.GetType() == model.MonitorTypeHTTPGET {
|
||||||
|
// SSL 证书变更报警
|
||||||
|
var last model.MonitorHistory
|
||||||
|
if err := dao.DB.Where("monitor_id = ?", r.GetId()).Order("id DESC").First(&last).Error; err == nil {
|
||||||
|
if last.Data != "" && last.Data != r.GetData() {
|
||||||
|
var monitor model.Monitor
|
||||||
|
dao.DB.First(&monitor, "id = ?", last.MonitorID)
|
||||||
|
alertmanager.SendNotification(fmt.Sprintf(
|
||||||
|
"监控:%s SSL证书变更,旧:%s,新:%s。",
|
||||||
|
monitor.Name, last.Data, r.GetData()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 存入历史记录
|
||||||
|
mh := model.PB2MonitorHistory(r)
|
||||||
|
if err := dao.DB.Create(&mh).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 更新最后检测时间
|
||||||
|
var m model.Monitor
|
||||||
|
m.ID = r.GetId()
|
||||||
|
if err := dao.DB.Model(&m).Update("last_check", time.Now()).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pb.Receipt{Proced: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) RequestTask(h *pb.Host, stream pb.NezhaService_RequestTaskServer) error {
|
||||||
|
var clientID uint64
|
||||||
|
var err error
|
||||||
|
if clientID, err = s.Auth.Check(stream.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
closeCh := make(chan error)
|
||||||
|
dao.ServerLock.Lock()
|
||||||
|
dao.ServerList[clientID].TaskStream = stream
|
||||||
|
dao.ServerList[clientID].TaskClose = closeCh
|
||||||
|
dao.ServerLock.Unlock()
|
||||||
|
select {
|
||||||
|
case err = <-closeCh:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NezhaHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.Receipt, error) {
|
||||||
var clientID uint64
|
var clientID uint64
|
||||||
var err error
|
var err error
|
||||||
if clientID, err = s.Auth.Check(c); err != nil {
|
if clientID, err = s.Auth.Check(c); err != nil {
|
||||||
@ -32,28 +78,7 @@ func (s *NezhaHandler) ReportState(c context.Context, r *pb.State) (*pb.Receipt,
|
|||||||
return &pb.Receipt{Proced: true}, nil
|
return &pb.Receipt{Proced: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heartbeat ..
|
func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Receipt, error) {
|
||||||
func (s *NezhaHandler) Heartbeat(r *pb.Beat, stream pb.NezhaService_HeartbeatServer) error {
|
|
||||||
var clientID uint64
|
|
||||||
var err error
|
|
||||||
defer log.Printf("Heartbeat exit server:%v err:%v", clientID, err)
|
|
||||||
if clientID, err = s.Auth.Check(stream.Context()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// 放入在线服务器列表
|
|
||||||
dao.ServerLock.RLock()
|
|
||||||
closeCh := make(chan error)
|
|
||||||
dao.ServerList[clientID].StreamClose = closeCh
|
|
||||||
dao.ServerList[clientID].Stream = stream
|
|
||||||
dao.ServerLock.RUnlock()
|
|
||||||
select {
|
|
||||||
case err = <-closeCh:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register ..
|
|
||||||
func (s *NezhaHandler) Register(c context.Context, r *pb.Host) (*pb.Receipt, error) {
|
|
||||||
var clientID uint64
|
var clientID uint64
|
||||||
var err error
|
var err error
|
||||||
if clientID, err = s.Auth.Check(c); err != nil {
|
if clientID, err = s.Auth.Check(c); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user