315 lines
9.5 KiB
Go
315 lines
9.5 KiB
Go
package maintenance
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"net/http"
|
||
"os"
|
||
"os/exec"
|
||
"path"
|
||
"runtime"
|
||
"time"
|
||
|
||
"nms_nbi/lib/core/utils/ctx"
|
||
"nms_nbi/lib/dborm"
|
||
"nms_nbi/lib/log"
|
||
"nms_nbi/lib/services"
|
||
"nms_nbi/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)
|
||
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))
|
||
}
|