314 lines
9.5 KiB
Go
314 lines
9.5 KiB
Go
package maintenance
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"runtime"
|
|
"time"
|
|
|
|
"be.ems/lib/core/utils/ctx"
|
|
"be.ems/lib/dborm"
|
|
"be.ems/lib/log"
|
|
"be.ems/lib/services"
|
|
"be.ems/restagent/config"
|
|
"github.com/shirou/gopsutil/cpu"
|
|
"github.com/shirou/gopsutil/disk"
|
|
"github.com/shirou/gopsutil/mem"
|
|
)
|
|
|
|
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理;
|
|
// 对于虚拟化部署OMC系统,能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控,提供界面截图 ;
|
|
|
|
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ;
|
|
|
|
// (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接 ;
|
|
|
|
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
|
|
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
|
|
|
|
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ;
|
|
// (7) 用户可以按照需求自定义报表模板并生成OMC系统维护数据报表,提供界面截图 ;
|
|
|
|
// (8) OMC具备自身告警管理功能,对于传统OMC系统,如:服务器单电源告警,存储硬盘告警、OMC系统软件故障等;
|
|
// 对于虚拟化OMC系统,如虚机告警、虚拟硬盘告警等,提供界面截图 。
|
|
|
|
var (
|
|
// parameter config management
|
|
Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz"
|
|
|
|
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理;
|
|
UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref"
|
|
|
|
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ;
|
|
UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog"
|
|
|
|
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ;
|
|
UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config"
|
|
|
|
// (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接
|
|
UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient"
|
|
|
|
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
|
|
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
|
|
UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top"
|
|
)
|
|
|
|
func init() {
|
|
// 定時收集 TODO
|
|
prefLogSave("")
|
|
}
|
|
|
|
func List(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Println("zz List")
|
|
services.ResponseStatusOK200Null(w)
|
|
}
|
|
|
|
// 性能指標
|
|
func prefInfo(dirName string) map[string]any {
|
|
data := make(map[string]any)
|
|
|
|
// 显示文件資源目录
|
|
dirPath := "D://"
|
|
if runtime.GOOS == "linux" {
|
|
dirPath = "/home"
|
|
}
|
|
// 訪問下級
|
|
if dirName != "" {
|
|
dirPath = path.Join(dirPath, dirName)
|
|
}
|
|
dir_list, e := os.ReadDir(dirPath)
|
|
if e != nil {
|
|
log.Error(e)
|
|
}
|
|
list := make([]map[string]any, 0)
|
|
for _, v := range dir_list {
|
|
o, err := v.Info()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
list = append(list, map[string]any{
|
|
"name": o.Name(),
|
|
"size": o.Size(),
|
|
"mode": o.Mode().String(),
|
|
"modTime": o.ModTime().Format("2006-01-02 15:04:05"),
|
|
"isDir": o.IsDir(),
|
|
})
|
|
}
|
|
data["dirList"] = list
|
|
|
|
// 文件資源使用率
|
|
u, _ := disk.Usage(dirPath)
|
|
usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1)
|
|
data["dirUse"] = fmt.Sprintf("%d", usedGB)
|
|
|
|
// CPU使用率
|
|
percent, err := cpu.Percent(time.Second, false)
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
data["cpuUse"] = fmt.Sprintf("%.2f", percent[0])
|
|
|
|
// 内存使用率
|
|
memInfo, err := mem.VirtualMemory()
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
data["memUse"] = memInfo.UsedPercent
|
|
|
|
// 獲取數據庫占用空間
|
|
if dborm.DbClient.XEngine != nil {
|
|
conf := config.GetYamlConfig()
|
|
result, err := dborm.DbClient.XEngine.QueryString(`SELECT
|
|
CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
|
|
CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
|
|
CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
|
|
CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size
|
|
FROM information_schema.tables WHERE TABLE_SCHEMA = ?;
|
|
`, conf.Database.Name)
|
|
if err == nil {
|
|
data["dbInfo"] = result[0]
|
|
} else {
|
|
data["dbInfo"] = map[string]string{}
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
// 性能指標存入數據庫
|
|
func prefLogSave(dirName string) {
|
|
if dborm.DbClient.XEngine != nil {
|
|
data := prefInfo(dirName)
|
|
|
|
dirListByte, err := json.Marshal(data["dirList"])
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
dbInfoByte, err := json.Marshal(data["dbInfo"])
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data
|
|
(id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used)
|
|
VALUES(NULL, NOW(), ?, ?, ?, ?, ?);
|
|
`, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"])
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
fmt.Println(rse.LastInsertId())
|
|
}
|
|
}
|
|
|
|
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true
|
|
func Pref(w http.ResponseWriter, r *http.Request) {
|
|
// 知道下級文件資源目录
|
|
dirName := r.URL.Query().Get("dirName")
|
|
data := prefInfo(dirName)
|
|
services.ResponseWithJson(w, http.StatusOK, data)
|
|
}
|
|
|
|
// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config
|
|
func Config(w http.ResponseWriter, r *http.Request) {
|
|
// json 請求參數獲取
|
|
var bodyArgs struct {
|
|
Key string `json:"key"`
|
|
Value string `json:"value"`
|
|
}
|
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
|
if err != nil {
|
|
log.Error("io.ReadAll is failed:", err)
|
|
services.ResponseNotFound404UriNotExist(w, r)
|
|
return
|
|
}
|
|
|
|
// 進行值更新
|
|
if dborm.DbClient.XEngine != nil {
|
|
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
fmt.Println(result)
|
|
rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
fmt.Println(rse)
|
|
}
|
|
|
|
services.ResponseStatusOK200Null(w)
|
|
}
|
|
|
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close
|
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet
|
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user
|
|
func SqlClient(w http.ResponseWriter, r *http.Request) {
|
|
// 关闭
|
|
isClose := r.URL.Query().Get("type")
|
|
if isClose == "close" && dborm.DbClient.XEngine != nil {
|
|
dborm.DbClient.XEngine.Close()
|
|
}
|
|
|
|
// 重连
|
|
isConnet := r.URL.Query().Get("type")
|
|
if isConnet == "connet" && dborm.DbClient.XEngine == nil {
|
|
conf := config.GetYamlConfig()
|
|
err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
|
|
conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
|
|
if err != nil {
|
|
fmt.Println("dborm.initDbClient err:", err)
|
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
|
return
|
|
}
|
|
}
|
|
|
|
// 查询实例
|
|
isUser := r.URL.Query().Get("type")
|
|
if isUser == "user" && dborm.DbClient.XEngine != nil {
|
|
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
fmt.Println(result)
|
|
rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
fmt.Println(rse)
|
|
}
|
|
|
|
// 进行连接测试
|
|
err := dborm.DbClient.XEngine.Ping()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
services.ResponseStatusOK200Null(w)
|
|
}
|
|
|
|
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep=
|
|
func Top(w http.ResponseWriter, r *http.Request) {
|
|
// 過濾命令
|
|
grep := r.URL.Query().Get("grep")
|
|
// 命令拼接
|
|
var cmd *exec.Cmd
|
|
switch runtime.GOOS {
|
|
case "linux":
|
|
command := "ps -ef "
|
|
if grep != "" {
|
|
command += grep
|
|
}
|
|
cmd = exec.Command(command)
|
|
case "windows":
|
|
command := "wmic process list brief "
|
|
if grep != "" {
|
|
command += grep
|
|
}
|
|
cmd = exec.Command("cmd", "/C", command)
|
|
}
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
fmt.Println(string(out))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
services.ResponseWithJson(w, http.StatusOK, string(out))
|
|
}
|
|
|
|
// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name=
|
|
func TopOps(w http.ResponseWriter, r *http.Request) {
|
|
// json 請求參數獲取
|
|
var bodyArgs struct {
|
|
Ops string `json:"ops"`
|
|
Pid string `json:"pid"`
|
|
}
|
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
|
if err != nil {
|
|
log.Error("io.ReadAll is failed:", err)
|
|
services.ResponseNotFound404UriNotExist(w, r)
|
|
return
|
|
}
|
|
// 命令拼接
|
|
var cmd *exec.Cmd
|
|
switch runtime.GOOS {
|
|
case "linux":
|
|
switch bodyArgs.Ops {
|
|
case "kill":
|
|
cmd = exec.Command("kill", "-9", bodyArgs.Pid)
|
|
}
|
|
case "windows":
|
|
switch bodyArgs.Ops {
|
|
case "kill":
|
|
cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F")
|
|
}
|
|
}
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
fmt.Println(string(out))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
services.ResponseWithJson(w, http.StatusOK, string(out))
|
|
}
|