✨ 批量更新 Agent
This commit is contained in:
		
							parent
							
								
									f0e0867a3d
								
							
						
					
					
						commit
						58d17b69a1
					
				@ -26,14 +26,13 @@ builds:
 | 
				
			|||||||
    binary: nezha-agent
 | 
					    binary: nezha-agent
 | 
				
			||||||
universal_binaries:
 | 
					universal_binaries:
 | 
				
			||||||
  - name_template: "nezha-agent"
 | 
					  - name_template: "nezha-agent"
 | 
				
			||||||
    replace: true
 | 
					    replace: false
 | 
				
			||||||
checksum:
 | 
					checksum:
 | 
				
			||||||
  name_template: "checksums.txt"
 | 
					  name_template: "checksums.txt"
 | 
				
			||||||
snapshot:
 | 
					snapshot:
 | 
				
			||||||
  name_template: "nezha-agent"
 | 
					  name_template: "nezha-agent"
 | 
				
			||||||
archives:
 | 
					archives:
 | 
				
			||||||
  - name_template: "nezha-agent_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
 | 
					  - name_template: "nezha-agent_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
 | 
				
			||||||
    allow_different_binary_count: true
 | 
					 | 
				
			||||||
    files:
 | 
					    files:
 | 
				
			||||||
      - none*
 | 
					      - none*
 | 
				
			||||||
changelog:
 | 
					changelog:
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
					  <small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
 | 
				
			||||||
  <br><br>
 | 
					  <br><br>
 | 
				
			||||||
<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.10.6&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.7.1-brightgreen?style=for-the-badge&logo=linux">
 | 
					<img src="https://img.shields.io/github/workflow/status/naiba/nezha/Dashboard%20image?label=Dash%20v0.10.7&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/naiba/nezha?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/workflow/status/naiba/nezha/Agent%20release?label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.7.1-brightgreen?style=for-the-badge&logo=linux">
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <br>
 | 
					  <br>
 | 
				
			||||||
  <p>:trollface: <b>哪吒监控</b> 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,计划任务和在线终端。</p>
 | 
					  <p>:trollface: <b>哪吒监控</b> 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,计划任务和在线终端。</p>
 | 
				
			||||||
@ -45,7 +45,8 @@ _\* 使用 WatchTower 可以自动更新面板,Windows 终端可以使用 nssm
 | 
				
			|||||||
- `--report-delay` 系统信息上报的间隔,默认为 1 秒,可以设置为 3 来进一步降低 agent 端系统资源占用(配置区间 1-4)
 | 
					- `--report-delay` 系统信息上报的间隔,默认为 1 秒,可以设置为 3 来进一步降低 agent 端系统资源占用(配置区间 1-4)
 | 
				
			||||||
- `--skip-conn` 不监控连接数,机场/连接密集型机器推荐设置,不然比较占 CPU([shirou/gopsutil/issues#220](https://github.com/shirou/gopsutil/issues/220))
 | 
					- `--skip-conn` 不监控连接数,机场/连接密集型机器推荐设置,不然比较占 CPU([shirou/gopsutil/issues#220](https://github.com/shirou/gopsutil/issues/220))
 | 
				
			||||||
- `--skip-procs` 不监控进程数,也可以降低 agent 占用
 | 
					- `--skip-procs` 不监控进程数,也可以降低 agent 占用
 | 
				
			||||||
- `--disable-auto-update` 禁止 Agent 自动更新(安全特性)
 | 
					- `--disable-auto-update` 禁止 **自动更新** Agent(安全特性)
 | 
				
			||||||
 | 
					- `--disable-force-update` 禁止 **强制更新** Agent(安全特性)
 | 
				
			||||||
- `--disable-command-execute` 禁止在 Agent 机器上执行定时任务、打开在线终端(安全特性)
 | 
					- `--disable-command-execute` 禁止在 Agent 机器上执行定时任务、打开在线终端(安全特性)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 功能说明
 | 
					## 功能说明
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,7 @@ type AgentConfig struct {
 | 
				
			|||||||
	SkipConnectionCount   bool
 | 
						SkipConnectionCount   bool
 | 
				
			||||||
	SkipProcsCount        bool
 | 
						SkipProcsCount        bool
 | 
				
			||||||
	DisableAutoUpdate     bool
 | 
						DisableAutoUpdate     bool
 | 
				
			||||||
 | 
						DisableForceUpdate    bool
 | 
				
			||||||
	DisableCommandExecute bool
 | 
						DisableCommandExecute bool
 | 
				
			||||||
	Debug                 bool
 | 
						Debug                 bool
 | 
				
			||||||
	Server                string
 | 
						Server                string
 | 
				
			||||||
@ -78,6 +79,7 @@ func main() {
 | 
				
			|||||||
	flag.BoolVar(&agentConf.SkipProcsCount, "skip-procs", false, "不监控进程数")
 | 
						flag.BoolVar(&agentConf.SkipProcsCount, "skip-procs", false, "不监控进程数")
 | 
				
			||||||
	flag.BoolVar(&agentConf.DisableCommandExecute, "disable-command-execute", false, "禁止在此机器上执行命令")
 | 
						flag.BoolVar(&agentConf.DisableCommandExecute, "disable-command-execute", false, "禁止在此机器上执行命令")
 | 
				
			||||||
	flag.BoolVar(&agentConf.DisableAutoUpdate, "disable-auto-update", false, "禁用自动升级")
 | 
						flag.BoolVar(&agentConf.DisableAutoUpdate, "disable-auto-update", false, "禁用自动升级")
 | 
				
			||||||
 | 
						flag.BoolVar(&agentConf.DisableForceUpdate, "disable-force-update", false, "禁用强制升级")
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if agentConf.ClientSecret == "" {
 | 
						if agentConf.ClientSecret == "" {
 | 
				
			||||||
@ -114,7 +116,7 @@ func run() {
 | 
				
			|||||||
						time.Sleep(time.Minute * 20)
 | 
											time.Sleep(time.Minute * 20)
 | 
				
			||||||
						updateCh <- struct{}{}
 | 
											updateCh <- struct{}{}
 | 
				
			||||||
					}()
 | 
										}()
 | 
				
			||||||
					doSelfUpdate()
 | 
										doSelfUpdate(false)
 | 
				
			||||||
				}()
 | 
									}()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
@ -236,8 +238,11 @@ func reportState() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func doSelfUpdate() {
 | 
					func doSelfUpdate(donNotUseLocalVersion bool) {
 | 
				
			||||||
	v := semver.MustParse(version)
 | 
						v := semver.MustParse("0.1.0")
 | 
				
			||||||
 | 
						if !donNotUseLocalVersion {
 | 
				
			||||||
 | 
							v = semver.MustParse(version)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	println("检查更新:", v)
 | 
						println("检查更新:", v)
 | 
				
			||||||
	latest, err := selfupdate.UpdateSelf(v, "naiba/nezha")
 | 
						latest, err := selfupdate.UpdateSelf(v, "naiba/nezha")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -250,7 +255,7 @@ func doSelfUpdate() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleUpgradeTask(task *pb.Task, result *pb.TaskResult) {
 | 
					func handleUpgradeTask(task *pb.Task, result *pb.TaskResult) {
 | 
				
			||||||
	doSelfUpdate()
 | 
						doSelfUpdate(true)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleTcpPingTask(task *pb.Task, result *pb.TaskResult) {
 | 
					func handleTcpPingTask(task *pb.Task, result *pb.TaskResult) {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"html/template"
 | 
						"html/template"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@ -28,6 +29,9 @@ func ServeWeb(port uint) *http.Server {
 | 
				
			|||||||
		"tf": func(t time.Time) string {
 | 
							"tf": func(t time.Time) string {
 | 
				
			||||||
			return t.Format("2006年1月2号 15:04:05")
 | 
								return t.Format("2006年1月2号 15:04:05")
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							"len": func(slice []interface{}) string {
 | 
				
			||||||
 | 
								return strconv.Itoa(len(slice))
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		"safe": func(s string) template.HTML {
 | 
							"safe": func(s string) template.HTML {
 | 
				
			||||||
			return template.HTML(s) // #nosec
 | 
								return template.HTML(s) // #nosec
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package controller
 | 
					package controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@ -14,6 +15,7 @@ import (
 | 
				
			|||||||
	"github.com/naiba/nezha/model"
 | 
						"github.com/naiba/nezha/model"
 | 
				
			||||||
	"github.com/naiba/nezha/pkg/mygin"
 | 
						"github.com/naiba/nezha/pkg/mygin"
 | 
				
			||||||
	"github.com/naiba/nezha/pkg/utils"
 | 
						"github.com/naiba/nezha/pkg/utils"
 | 
				
			||||||
 | 
						"github.com/naiba/nezha/proto"
 | 
				
			||||||
	"github.com/naiba/nezha/service/dao"
 | 
						"github.com/naiba/nezha/service/dao"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,6 +38,7 @@ func (ma *memberAPI) serve() {
 | 
				
			|||||||
	mr.POST("/monitor", ma.addOrEditMonitor)
 | 
						mr.POST("/monitor", ma.addOrEditMonitor)
 | 
				
			||||||
	mr.POST("/cron", ma.addOrEditCron)
 | 
						mr.POST("/cron", ma.addOrEditCron)
 | 
				
			||||||
	mr.GET("/cron/:id/manual", ma.manualTrigger)
 | 
						mr.GET("/cron/:id/manual", ma.manualTrigger)
 | 
				
			||||||
 | 
						mr.POST("/force-update", ma.forceUpdate)
 | 
				
			||||||
	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)
 | 
				
			||||||
@ -322,6 +325,41 @@ func (ma *memberAPI) manualTrigger(c *gin.Context) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ma *memberAPI) forceUpdate(c *gin.Context) {
 | 
				
			||||||
 | 
						var forceUpdateServers []uint64
 | 
				
			||||||
 | 
						if err := c.ShouldBindJSON(&forceUpdateServers); err != nil {
 | 
				
			||||||
 | 
							c.JSON(http.StatusOK, model.Response{
 | 
				
			||||||
 | 
								Code:    http.StatusBadRequest,
 | 
				
			||||||
 | 
								Message: err.Error(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var executeResult bytes.Buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < len(forceUpdateServers); i++ {
 | 
				
			||||||
 | 
							dao.ServerLock.RLock()
 | 
				
			||||||
 | 
							server := dao.ServerList[forceUpdateServers[i]]
 | 
				
			||||||
 | 
							dao.ServerLock.RUnlock()
 | 
				
			||||||
 | 
							if server != nil && server.TaskStream != nil {
 | 
				
			||||||
 | 
								if err := server.TaskStream.Send(&proto.Task{
 | 
				
			||||||
 | 
									Type: model.TaskTypeUpgrade,
 | 
				
			||||||
 | 
								}); err != nil {
 | 
				
			||||||
 | 
									executeResult.WriteString(fmt.Sprintf("%d 下发指令失败 %+v<br/>", forceUpdateServers[i], err))
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									executeResult.WriteString(fmt.Sprintf("%d 下发指令成功<br/>", forceUpdateServers[i]))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								executeResult.WriteString(fmt.Sprintf("%d 离线<br/>", forceUpdateServers[i]))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.JSON(http.StatusOK, model.Response{
 | 
				
			||||||
 | 
							Code:    http.StatusOK,
 | 
				
			||||||
 | 
							Message: executeResult.String(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type notificationForm struct {
 | 
					type notificationForm struct {
 | 
				
			||||||
	ID            uint64
 | 
						ID            uint64
 | 
				
			||||||
	Name          string
 | 
						Name          string
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							@ -23,14 +23,13 @@ require (
 | 
				
			|||||||
	github.com/patrickmn/go-cache v2.1.0+incompatible
 | 
						github.com/patrickmn/go-cache v2.1.0+incompatible
 | 
				
			||||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
						github.com/pkg/errors v0.9.1 // indirect
 | 
				
			||||||
	github.com/robfig/cron/v3 v3.0.1
 | 
						github.com/robfig/cron/v3 v3.0.1
 | 
				
			||||||
	github.com/shirou/gopsutil/v3 v3.21.8
 | 
						github.com/shirou/gopsutil/v3 v3.21.10
 | 
				
			||||||
	github.com/spf13/pflag v1.0.3
 | 
						github.com/spf13/pflag v1.0.3
 | 
				
			||||||
	github.com/spf13/viper v1.7.1
 | 
						github.com/spf13/viper v1.7.1
 | 
				
			||||||
	github.com/stretchr/testify v1.7.0
 | 
						github.com/stretchr/testify v1.7.0
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
 | 
						golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
 | 
				
			||||||
	golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect
 | 
						golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect
 | 
				
			||||||
	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
 | 
						golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
 | 
					 | 
				
			||||||
	google.golang.org/grpc v1.33.1
 | 
						google.golang.org/grpc v1.33.1
 | 
				
			||||||
	google.golang.org/protobuf v1.25.0
 | 
						google.golang.org/protobuf v1.25.0
 | 
				
			||||||
	gopkg.in/yaml.v2 v2.2.8
 | 
						gopkg.in/yaml.v2 v2.2.8
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								go.sum
									
									
									
									
									
								
							@ -94,8 +94,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
 | 
				
			|||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
					github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
				
			||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
					github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
				
			||||||
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.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
 | 
					 | 
				
			||||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 | 
					github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 | 
				
			||||||
 | 
					github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
 | 
				
			||||||
 | 
					github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 | 
				
			||||||
github.com/go-ping/ping v0.0.0-20210407214646-e4e642a95741 h1:b0sLP++Tsle+s57tqg5sUk1/OQsC6yMCciVeqNzOcwU=
 | 
					github.com/go-ping/ping v0.0.0-20210407214646-e4e642a95741 h1:b0sLP++Tsle+s57tqg5sUk1/OQsC6yMCciVeqNzOcwU=
 | 
				
			||||||
github.com/go-ping/ping v0.0.0-20210407214646-e4e642a95741/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI=
 | 
					github.com/go-ping/ping v0.0.0-20210407214646-e4e642a95741/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=
 | 
				
			||||||
@ -144,8 +145,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 | 
				
			|||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 | 
				
			||||||
 | 
					github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 | 
					github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 | 
				
			||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 | 
					github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 | 
				
			||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
 | 
					github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
 | 
				
			||||||
@ -225,6 +227,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
				
			|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
					github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
				
			||||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 | 
					github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 | 
				
			||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 | 
					github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 | 
				
			||||||
 | 
					github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
 | 
				
			||||||
 | 
					github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 | 
				
			||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 | 
					github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 | 
				
			||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 | 
					github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 | 
				
			||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 | 
					github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 | 
				
			||||||
@ -290,8 +294,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
 | 
				
			|||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 | 
					github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 | 
				
			||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 | 
					github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 | 
				
			||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 | 
					github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 | 
				
			||||||
github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA=
 | 
					github.com/shirou/gopsutil/v3 v3.21.10 h1:flTg1DrnV/UVrBqjLgVgDJzx6lf+91rC64/dBHmO2IA=
 | 
				
			||||||
github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
 | 
					github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew=
 | 
				
			||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
					github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
				
			||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 | 
					github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 | 
				
			||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 | 
					github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 | 
				
			||||||
@ -470,8 +474,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
 | 
					golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
 | 
				
			|||||||
@ -8,11 +8,15 @@
 | 
				
			|||||||
                <button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditServer()"><i
 | 
					                <button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditServer()"><i
 | 
				
			||||||
                        class="add icon"></i> 添加主机
 | 
					                        class="add icon"></i> 添加主机
 | 
				
			||||||
                </button>
 | 
					                </button>
 | 
				
			||||||
 | 
					                <button class="ui right labeled nezha-primary-btn icon button" onclick="forceUpdate()"><i
 | 
				
			||||||
 | 
					                        class="arrow alternate circle up outline icon"></i> 强制更新
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <table class="ui very basic table">
 | 
					        <table class="ui very basic table">
 | 
				
			||||||
            <thead>
 | 
					            <thead>
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <th><button onclick="checkAllServer()" class="ui mini nezha-primary-btn button">全选</button></th>
 | 
				
			||||||
                    <th>ID(排序)</th>
 | 
					                    <th>ID(排序)</th>
 | 
				
			||||||
                    <th>名称</th>
 | 
					                    <th>名称</th>
 | 
				
			||||||
                    <th>分组</th>
 | 
					                    <th>分组</th>
 | 
				
			||||||
@ -27,6 +31,7 @@
 | 
				
			|||||||
            <tbody>
 | 
					            <tbody>
 | 
				
			||||||
                {{range $server := .Servers}}
 | 
					                {{range $server := .Servers}}
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td><input type="checkbox" class="nezha-servers" value="{{$server.ID}}" /></td>
 | 
				
			||||||
                    <td>{{$server.ID}}({{$server.DisplayIndex}})</td>
 | 
					                    <td>{{$server.ID}}({{$server.DisplayIndex}})</td>
 | 
				
			||||||
                    <td>{{$server.Name}}</td>
 | 
					                    <td>{{$server.Name}}</td>
 | 
				
			||||||
                    <td>{{$server.Tag}}</td>
 | 
					                    <td>{{$server.Tag}}</td>
 | 
				
			||||||
@ -72,5 +77,57 @@
 | 
				
			|||||||
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>
 | 
					<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
    var clipboard = new ClipboardJS('.ui.icon.green.mini.button');
 | 
					    var clipboard = new ClipboardJS('.ui.icon.green.mini.button');
 | 
				
			||||||
 | 
					    const checkBoxList = document.querySelectorAll('tbody > tr > td > input.nezha-servers[type=checkbox]')
 | 
				
			||||||
 | 
					    function checkAllServer() {
 | 
				
			||||||
 | 
					        checkBoxList.forEach(cb => {
 | 
				
			||||||
 | 
					            cb.checked = true
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function forceUpdate() {
 | 
				
			||||||
 | 
					        const servers = []
 | 
				
			||||||
 | 
					        checkBoxList.forEach(cb => {
 | 
				
			||||||
 | 
					            if (cb.checked) {
 | 
				
			||||||
 | 
					                servers.push(parseInt(cb.value))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        if (servers.length == 0) {
 | 
				
			||||||
 | 
					            $.suiAlert({
 | 
				
			||||||
 | 
					                title: '当前没有选中的服务器',
 | 
				
			||||||
 | 
					                description: '',
 | 
				
			||||||
 | 
					                type: 'warning',
 | 
				
			||||||
 | 
					                time: '2',
 | 
				
			||||||
 | 
					                position: 'top-center',
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $.post('/api/force-update', JSON.stringify(servers))
 | 
				
			||||||
 | 
					            .then((resp) => {
 | 
				
			||||||
 | 
					                if (resp.code == 200) {
 | 
				
			||||||
 | 
					                    $.suiAlert({
 | 
				
			||||||
 | 
					                        title: '执行结果',
 | 
				
			||||||
 | 
					                        description: resp.message,
 | 
				
			||||||
 | 
					                        type: 'success',
 | 
				
			||||||
 | 
					                        time: '3',
 | 
				
			||||||
 | 
					                        position: 'top-center',
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    $.suiAlert({
 | 
				
			||||||
 | 
					                        title: '',
 | 
				
			||||||
 | 
					                        description: resp.message,
 | 
				
			||||||
 | 
					                        type: 'error',
 | 
				
			||||||
 | 
					                        time: '3',
 | 
				
			||||||
 | 
					                        position: 'top-center',
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }).catch(err => {
 | 
				
			||||||
 | 
					                $.suiAlert({
 | 
				
			||||||
 | 
					                    title: '',
 | 
				
			||||||
 | 
					                    description: err,
 | 
				
			||||||
 | 
					                    type: 'error',
 | 
				
			||||||
 | 
					                    time: '3',
 | 
				
			||||||
 | 
					                    position: 'top-center',
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
{{end}}
 | 
					{{end}}
 | 
				
			||||||
@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
	pb "github.com/naiba/nezha/proto"
 | 
						pb "github.com/naiba/nezha/proto"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Version = "v0.10.6" // !!记得修改 README 中的 badge 版本!!
 | 
					var Version = "v0.10.7" // !!记得修改 README 中的 badge 版本!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	Conf  *model.Config
 | 
						Conf  *model.Config
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user