diff --git a/README.md b/README.md index 5eae7f8..010f92b 100644 --- a/README.md +++ b/README.md @@ -32,19 +32,20 @@ MS-Agent: Installed on Zabbix Server, used to receive alarms generated by Zabbix ## Compatibility | Zabbix Version | Compatibility | -|:---------------| :------------ | -| 6.4.x | ✅ | -| 6.2.x | ✅ | -| 6.0.x | ✅ | -| 5.4.x | ✅ | -| 5.2.x | ✅ | -| 5.0.x LTS | ✅ | -| 4.4.x | ✅ | -| 4.2.x | ✅ | -| 4.0.x LTS | ✅ | -| 3.4.x | untested | -| 3.2.x | untested | -| 3.0.x LTS | untested | +|:---------------|:-------------:| +| 7.0.x LTS | ✅ | +| 6.4.x | ✅ | +| 6.2.x | ✅ | +| 6.0.x LTS | ✅ | +| 5.4.x | ✅ | +| 5.2.x | ✅ | +| 5.0.x LTS | ✅ | +| 4.4.x | ✅ | +| 4.2.x | ✅ | +| 4.0.x LTS | ✅ | +| 3.4.x | untested | +| 3.2.x | untested | +| 3.0.x LTS | untested | ## Documentation @@ -60,7 +61,7 @@ MS-Agent: Installed on Zabbix Server, used to receive alarms generated by Zabbix ## Compile -go >=1.21 +go >=1.22 ``` mkdir -p $GOPATH/src/github.com/canghai908 diff --git a/README.zh-CN.md b/README.zh-CN.md index 56ce0a4..e5ccbfa 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -32,20 +32,21 @@ MS-Agent: 安装在 Zabbix Server 上, 用于接收 Zabbix Server 产生的告 ## 兼容性 -| zabbix 版本 | 兼容性 | -|:----------| :----- | -| 6.4.x | ✅ | -| 6.2.x | ✅ | -| 6.0.x | ✅ | -| 5.4.x | ✅ | -| 5.2.x | ✅ | -| 5.0.x LTS | ✅ | -| 4.4.x | ✅ | -| 4.2.x | ✅ | -| 4.0.x LTS | ✅ | -| 3.4.x | 未测试 | -| 3.2.x | 未测试 | -| 3.0.x LTS | 未测试 | +| zabbix 版本 | 兼容性 | +|:-------------|:-------:| +| 7.0.x LTS | ✅ | +| 6.4.x | ✅ | +| 6.2.x | ✅ | +| 6.0.x LTS | ✅ | +| 5.4.x | ✅ | +| 5.2.x | ✅ | +| 5.0.x LTS | ✅ | +| 4.4.x | ✅ | +| 4.2.x | ✅ | +| 4.0.x LTS | ✅ | +| 3.4.x | 未测试 | +| 3.2.x | 未测试 | +| 3.0.x LTS | 未测试 | ## 文档 @@ -61,7 +62,7 @@ MS-Agent: 安装在 Zabbix Server 上, 用于接收 Zabbix Server 产生的告 ## 编译 -环境:go >=1.21 +环境:go >=1.22 ``` mkdir -p $GOPATH/src/github.com/canghai908 diff --git a/control b/control index 45c2f31..03a21b8 100755 --- a/control +++ b/control @@ -1,6 +1,6 @@ #!/bin/bash # release version -version=2.1.5 +version=2.1.6 CWD=$(cd $(dirname $0)/; pwd) cd $CWD diff --git a/controllers/host.go b/controllers/host.go index d59800d..83a88ef 100644 --- a/controllers/host.go +++ b/controllers/host.go @@ -24,6 +24,7 @@ func (c *HostController) URLMapping() { c.Mapping("getOneInterface", c.GetOneInterface) c.Mapping("GetMonWinFileSystem", c.GetMonWinFileSystem) c.Mapping("GetMonLinFileSystem", c.GetMonLinFileSystem) + c.Mapping("GetGraph", c.GetGraph) } // Post ... @@ -80,8 +81,6 @@ func (c *HostController) GetOne() { c.Data["json"] = v.Error } else { c.Data["json"] = v - c.ServeJSON() - return } c.ServeJSON() return @@ -258,3 +257,35 @@ func (c *HostController) GetMonLinFileSystem() { c.Data["json"] = HostInterfaceRes c.ServeJSON() } + +// GetGraph +// @Title 查看主机图形 +// @Description 查看图形 +// @Param X-Token header string true "x-token in header" +// @Param hostid path string ture "hostid" +// @Success 200 {object} models.MonItemList +// @Failure 403 +// @router /graph/:hostid [post] +func (c *HostController) GetGraph() { + var v models.GraphReq + err := json.Unmarshal(c.Ctx.Input.RequestBody, &v) + if err != nil { + HostInterfaceRes.Code = 500 + HostInterfaceRes.Message = err.Error() + c.Data["json"] = HostInterfaceRes + c.ServeJSON() + } + hostId := c.Ctx.Input.Param(":hostid") + hs, err := models.GetGraphData(hostId, v.Start, v.End) + if err != nil { + HostInterfaceRes.Code = 500 + HostInterfaceRes.Message = err.Error() + } else { + HostInterfaceRes.Code = 200 + HostInterfaceRes.Message = "获取数据成功" + HostInterfaceRes.Data.Items = hs + HostInterfaceRes.Data.Total = int64(len(hs)) + } + c.Data["json"] = HostInterfaceRes + c.ServeJSON() +} diff --git a/go.mod b/go.mod index d992162..c45b980 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/lib/pq v1.10.7 github.com/manifoldco/promptui v0.9.0 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pterm/pterm v0.12.75 github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49 github.com/shopspring/decimal v1.3.1 diff --git a/go.sum b/go.sum index 12e6a87..f753ab3 100644 --- a/go.sum +++ b/go.sum @@ -184,6 +184,8 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= diff --git a/models/base.go b/models/base.go index 7e20b94..0e4d7f4 100644 --- a/models/base.go +++ b/models/base.go @@ -167,8 +167,8 @@ func ModelsInit(zabbix_web, zabbix_user, zabbix_pass, zabbix_token, } logs.Info("Zabbix API connected!Zabbix version:", version) - //zabbix web login - // LoginZabbixWeb(zabbix_web, zabbix_user, zabbix_pass) + // zabbix web login + LoginZabbixWeb(zabbix_web, zabbix_user, zabbix_pass) //redis res_db, err := strconv.Atoi(redis_db) diff --git a/models/channel.go b/models/channel.go index 4fb8ed1..a3d1feb 100644 --- a/models/channel.go +++ b/models/channel.go @@ -12,7 +12,7 @@ import ( "zbxtable/utils" ) -//alert gen by rules +// alert gen by rules func GenAlert(alarm *Alarm) bool { o := orm.NewOrm() var rules []Rule @@ -143,31 +143,41 @@ func GenAlert(alarm *Alarm) bool { return true } -func GetEventUser(groupIds, userIds, channel string) (list []string, err error) { +// GetEventUser 查找事件用户信息 +func GetEventUser(groupIds, userIds string) (list []string, err error) { o := orm.NewOrm() - //get grouids - var group UserGroup - var gList []UserGroup - gids := strings.Split(groupIds, ",") - _, err = o.QueryTable(group).Filter("id__in", gids).All(&gList) - if err != nil { - return []string{}, err - } - //get group userid + //用户组信息,判断用户组是否为空 var guidList []string - if len(gList) != 0 { - for _, v := range gList { - ids := strings.Split(v.Member, ",") - for _, vv := range ids { - guidList = append(guidList, vv) + if groupIds != "" { + var group UserGroup + var gList []UserGroup + //组分隔 + gids := strings.Split(groupIds, ",") + _, err = o.QueryTable(group).Filter("id__in", gids).All(&gList) + if err != nil { + return + } + //get group userid + if len(gList) != 0 { + for _, v := range gList { + ids := strings.Split(v.Member, ",") + for _, vv := range ids { + guidList = append(guidList, vv) + } } } } + var ids []string uid := strings.Split(userIds, ",") + if len(guidList) != 0 { + //添加用户组 + ids = utils.UniqueArr(utils.MergeArr(guidList, uid)) + } else { + //添加用户 + ids = uid + } //get all userids unique - ids := utils.UniqueArr(utils.MergeArr(guidList, uid)) if len(ids) != 0 { - var user Manager var plist []Manager _, err = o.QueryTable(user).Filter("id__in", ids).All(&plist, "id", "username", @@ -204,8 +214,8 @@ func sendEvent(event *Event) { } continue } - //popuser - toUsers, err := GetEventUser(event.GroupIds, event.UserIds, v) + //GetEventUser + toUsers, err := GetEventUser(event.GroupIds, event.UserIds) if err != nil { logs.Error(err) return @@ -237,7 +247,7 @@ func sendEvent(event *Event) { } } -//mut +// mut func IsMuted(event *Event) bool { o := orm.NewOrm() var rules []Rule @@ -280,7 +290,7 @@ func IsMuted(event *Event) bool { return false } -//IsMuteTime not +// IsMuteTime not func IsMuteTime(event *Event, rule *Rule) bool { stime, _ := utils.ParTime(rule.Stime) etime, _ := utils.ParTime(rule.Etime) diff --git a/models/cron.go b/models/cron.go index 722d1c8..cc7d421 100644 --- a/models/cron.go +++ b/models/cron.go @@ -339,7 +339,6 @@ func GetTypeHostList() error { p, _, err := GetHostsList(v) if err != nil { logs.Error(err) - return err continue } //hosts info to redis @@ -350,7 +349,6 @@ func GetTypeHostList() error { err = RDB.Set(ctx, v+"_OVERVIEW", string(hostsdata), 3600*time.Second).Err() if err != nil { logs.Error(err) - return err continue } //inventor info to redis @@ -375,7 +373,6 @@ func GetTypeHostList() error { err = RDB.Set(ctx, v+"_INVENTORY", string(data), 3600*time.Second).Err() if err != nil { logs.Error(err) - return err continue } } @@ -392,7 +389,7 @@ func EgressCache() error { } var itemlist []string //空返回 - if v.InOne == "" || v.OutOne == "" || v.InTwo == "" || v.OutTwo == "" { + if v.InOne == "" && v.OutOne == "" && v.InTwo == "" && v.OutTwo == "" { var dList EgressList dList.NameOne = v.NameOne dList.InOne = "0Kb/s" diff --git a/models/host.go b/models/host.go index a1bd53e..66986b5 100644 --- a/models/host.go +++ b/models/host.go @@ -3,10 +3,12 @@ package models import ( "context" "errors" + "fmt" "github.com/astaxie/beego/logs" "math" "strconv" "strings" + "sync" "zbxtable/utils" ) @@ -15,8 +17,12 @@ func HostsList(HostType, page, limit, hosts, model, ip, available string) ([]Hos SelectInterfacesPar := []string{"ip", "port", "available", "error"} SearchInventoryInventoryPar := make(map[string]string) SearchInventoryInventoryPar["type"] = HostType + filterPar := make(map[string]string) + filterPar["status"] = "0" + //old version rep, err := API.CallWithError("host.get", Params{ "output": "extend", + "filter": filterPar, "searchInventory": SearchInventoryInventoryPar, "selectInventory": "extend", "selectInterfaces": SelectInterfacesPar}) @@ -676,6 +682,7 @@ func GetHostsList(HostType string) ([]Hosts, int64, error) { // GetLinFilesSystemData linux文件系统数据获取 func GetLinFilesSystemData(hostid string) ([]LinFilesSystemData, error) { + //新版本 if ZBX_V { ItemsOutput := []string{"itemid", "tags", "value_type", "name", "key_", "delay", "units", "lastvalue", "lastclock"} selectTags := []string{"tag", "value"} @@ -702,63 +709,54 @@ func GetLinFilesSystemData(hostid string) ([]LinFilesSystemData, error) { if err != nil { return []LinFilesSystemData{}, err } - var TagsList []LinFilesSystemData - var Tags LinFilesSystemData - var count, rootcount int64 - count = 0 - rootcount = 0 - // + var linFilesystemData []LinFilesSystemData + filesystemData := make(map[string]map[string]interface{}) + //遍历文件系统数据 for _, v := range ts { for _, vv := range v.Tags { if vv.Tag == "filesystem" || strings.Contains(vv.Value, "Filesystem") { - //root / - if vv.Value == "/" { - Tags.Name = vv.Value - switch { - case v.Key == "vfs.fs.size["+vv.Value+",used]": - Tags.UsedSpace = utils.InterfaceStrToInt64(v.Lastvalue) - rootcount++ - case v.Key == "vfs.fs.inode["+vv.Value+",pfree]": - Tags.InodesPUsed = utils.Float64Round2(float64(100) - utils.DecFloat64Round2(v.Lastvalue)) - Tags.Lastclock = v.Lastclock - rootcount++ - case v.Key == "vfs.fs.size["+vv.Value+",pused]": - Tags.SpaceUtilization = utils.DecFloat64Round2(v.Lastvalue) - rootcount++ - case v.Key == "vfs.fs.size["+vv.Value+",total]": - Tags.TotalSpace = utils.InterfaceStrToInt64(v.Lastvalue) - rootcount++ - } - if rootcount%4 == 0 { - TagsList = append(TagsList, Tags) - - } - } else { - //if strings.Contains(v.Name, vv.Value) && vv.Value != "/" { - Tags.Name = vv.Value - switch { - case v.Key == "vfs.fs.size["+vv.Value+",used]": - Tags.UsedSpace = utils.InterfaceStrToInt64(v.Lastvalue) - count++ - case v.Key == "vfs.fs.inode["+vv.Value+",pfree]": - Tags.InodesPUsed = utils.Float64Round2(float64(100) - utils.DecFloat64Round2(v.Lastvalue)) - Tags.Lastclock = v.Lastclock - count++ - case v.Key == "vfs.fs.size["+vv.Value+",pused]": - Tags.SpaceUtilization = utils.DecFloat64Round2(v.Lastvalue) - count++ - case v.Key == "vfs.fs.size["+vv.Value+",total]": - Tags.TotalSpace = utils.InterfaceStrToInt64(v.Lastvalue) - count++ - } - if count%4 == 0 { - TagsList = append(TagsList, Tags) - } //} + fsData, ok := filesystemData[vv.Value] + if !ok { + fsData = make(map[string]interface{}) + filesystemData[vv.Value] = fsData + } + switch v.Key { + case "vfs.fs.size[" + vv.Value + ",used]", "vfs.fs.dependent.size[" + vv.Value + ",used]": + fsData["UsedSpace"] = utils.InterfaceStrToInt64(v.Lastvalue) + case "vfs.fs.inode[" + vv.Value + ",pfree]", "vfs.fs.dependent.inode[" + vv.Value + ",pfree]": + fsData["InodesPUsed"] = utils.Float64Round2(float64(100) - utils.DecFloat64Round2(v.Lastvalue)) + fsData["Lastclock"] = v.Lastclock + case "vfs.fs.size[" + vv.Value + ",pused]", "vfs.fs.dependent.size[" + vv.Value + ",pused]": + fsData["SpaceUtilization"] = utils.DecFloat64Round2(v.Lastvalue) + case "vfs.fs.size[" + vv.Value + ",total]", "vfs.fs.dependent.size[" + vv.Value + ",total]": + fsData["TotalSpace"] = utils.InterfaceStrToInt64(v.Lastvalue) } } } } - return TagsList, nil + // 将 map 转换为 LinFilesSystemData 切片 + for name, data := range filesystemData { + fsData := LinFilesSystemData{ + Name: name, + } + if usedSpace, ok := data["UsedSpace"].(int64); ok { + fsData.UsedSpace = usedSpace + } + if inodesPUsed, ok := data["InodesPUsed"].(float64); ok { + fsData.InodesPUsed = inodesPUsed + } + if spaceUtilization, ok := data["SpaceUtilization"].(float64); ok { + fsData.SpaceUtilization = spaceUtilization + } + if totalSpace, ok := data["TotalSpace"].(int64); ok { + fsData.TotalSpace = totalSpace + } + if lastclock, ok := data["Lastclock"].(string); ok { + fsData.Lastclock = lastclock + } + linFilesystemData = append(linFilesystemData, fsData) + } + return linFilesystemData, nil } //5.4以下版本处理 selectItemsPar := []string{"itemid", "value_type", "name", "key_", "delay", "units", "lastvalue", "lastclock"} @@ -799,6 +797,9 @@ func GetLinFilesSystemData(hostid string) ([]LinFilesSystemData, error) { return list, nil } +func (fsData *LinFilesSystemData) isComplete() bool { + return fsData.UsedSpace != 0 && fsData.InodesPUsed != 0 && fsData.SpaceUtilization != 0 && fsData.TotalSpace != 0 +} // GetWinFilesSystemData windows文件系统获取 func GetWinFilesSystemData(hostid string) ([]WinFilesSystemData, error) { @@ -824,41 +825,56 @@ func GetWinFilesSystemData(hostid string) ([]WinFilesSystemData, error) { if err != nil { return []WinFilesSystemData{}, err } - var ts []MonIts err = json.Unmarshal(ApplicationResByte, &ts) if err != nil { return []WinFilesSystemData{}, err } - var TagsList []WinFilesSystemData - var Tags WinFilesSystemData - var count int64 - count = 0 + var fileList []WinFilesSystemData + filesystemData := make(map[string]map[string]interface{}) for _, v := range ts { for _, vv := range v.Tags { if vv.Tag == "filesystem" { if strings.Contains(v.Name, vv.Value) { - Tags.Name = vv.Value - switch { - case v.Key == "vfs.fs.size["+vv.Value+",pused]": - Tags.SpaceUtilization = utils.DecFloat64Round2(v.Lastvalue) - Tags.Lastclock = v.Lastclock - count++ - case v.Key == "vfs.fs.size["+vv.Value+",total]": - Tags.TotalSpace = utils.InterfaceStrToInt64(v.Lastvalue) - count++ - case v.Key == "vfs.fs.size["+vv.Value+",used]": - Tags.UsedSpace = utils.InterfaceStrToInt64(v.Lastvalue) - count++ + fsData, ok := filesystemData[vv.Value] + if !ok { + fsData = make(map[string]interface{}) + filesystemData[vv.Value] = fsData } - if count%3 == 0 { - TagsList = append(TagsList, Tags) + switch v.Key { + case "vfs.fs.size[" + vv.Value + ",pused]", "vfs.fs.dependent.size[" + vv.Value + ",pused]": + fmt.Println("vfs.fs.size["+vv.Value+",pused]", v.Lastvalue) + fsData["SpaceUtilization"] = utils.DecFloat64Round2(v.Lastvalue) + fsData["Lastclock"] = v.Lastclock + case "vfs.fs.size[" + vv.Value + ",total]", "vfs.fs.dependent.size[" + vv.Value + ",total]": + fsData["TotalSpace"] = utils.InterfaceStrToInt64(v.Lastvalue) + case "vfs.fs.size[" + vv.Value + ",used]", "vfs.fs.dependent.size[" + vv.Value + ",used]": + fsData["UsedSpace"] = utils.InterfaceStrToInt64(v.Lastvalue) } } } } } - return TagsList, nil + // 将 map 转换为 LinFilesSystemData 切片 + for name, data := range filesystemData { + fsData := WinFilesSystemData{ + Name: name, + } + if usedSpace, ok := data["UsedSpace"].(int64); ok { + fsData.UsedSpace = usedSpace + } + if spaceUtilization, ok := data["SpaceUtilization"].(float64); ok { + fsData.SpaceUtilization = spaceUtilization + } + if totalSpace, ok := data["TotalSpace"].(int64); ok { + fsData.TotalSpace = totalSpace + } + if lastclock, ok := data["Lastclock"].(string); ok { + fsData.Lastclock = lastclock + } + fileList = append(fileList, fsData) + } + return fileList, nil } //5.4以下版本处理 selectItemsPar := []string{"itemid", "value_type", "name", "key_", "delay", "units", "lastvalue", "lastclock"} @@ -932,3 +948,61 @@ func GetMonLinData(hostid string) (mon MonLinData, err error) { mo.InterfacesTotal = int64(len(interfaces)) return mo, nil } + +type PNGData struct { + Name string `json:"name"` + Png string `json:"png"` +} +type GraphReq struct { + Start string `json:"start"` + End string `json:"end"` +} + +// GetGraphData 查看主机的图形数据 +func GetGraphData(hostId, start, end string) ([]PNGData, error) { + var pngData []PNGData + selectItemsPar := []string{"graphid", "name"} + //Key2Par := []string{"system.cpu.util", "vm.memory.utilization", "vm.memory.size"} + //Search2Par := make(map[string][]string) + //Search2Par["key_"] = Key2Par + p, err := API.CallWithError("graph.get", Params{ + "output": selectItemsPar, + "hostids": hostId, + "searchByAny": true, + //"search": Search2Par, + "sortfield": "graphid"}) + if err != nil { + return pngData, nil + } + st, err := json.Marshal(p.Result) + if err != nil { + return pngData, nil + } + var hba []GraphData + err = json.Unmarshal(st, &hba) + if err != nil { + return pngData, nil + + } + var wg sync.WaitGroup + pngDataChan := make(chan PNGData, len(hba)) + for _, v := range hba { + wg.Add(1) + go func(v GraphData) { + defer wg.Done() + png, _ := GetPNGGraph(v.GraphId, start, end) + pngDataChan <- PNGData{ + Name: v.Name, + Png: png, + } + }(v) + } + go func() { + wg.Wait() + close(pngDataChan) + }() + for data := range pngDataChan { + pngData = append(pngData, data) + } + return pngData, nil +} diff --git a/models/host_mod.go b/models/host_mod.go index 265ce7a..56f893a 100644 --- a/models/host_mod.go +++ b/models/host_mod.go @@ -357,3 +357,7 @@ type MonLinData struct { Interfaces []InterfaceData `json:"interfaces"` InterfacesTotal int64 `json:"interfaces_total"` } +type GraphData struct { + GraphId string `json:"graphid"` + Name string `json:"name"` +} diff --git a/models/images.go b/models/images.go index 966322e..628a9ba 100644 --- a/models/images.go +++ b/models/images.go @@ -4,6 +4,7 @@ import ( "bytes" "compress/gzip" "crypto/tls" + "encoding/base64" "github.com/astaxie/beego/logs" "io" "net/http" @@ -14,7 +15,7 @@ import ( "github.com/signintech/gopdf" ) -//SaveImagePDF 导出图形到PDF +// SaveImagePDF 导出图形到PDF func SaveImagePDF(hostids []string, start, end string) ([]byte, error) { pdf := gopdf.GoPdf{} pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) @@ -97,7 +98,7 @@ func SaveImagePDF(hostids []string, start, end string) ([]byte, error) { return b.Bytes(), nil } -//GetPdfImageHolder func +// GetPdfImageHolder func func GetPdfImageHolder(grupinfo GraphInfo, start, end string, wg *sync.WaitGroup, pdfHolder chan<- gopdf.ImageHolder) { defer wg.Done() //请求图形 @@ -151,3 +152,65 @@ func GetPdfImageHolder(grupinfo GraphInfo, start, end string, wg *sync.WaitGroup pdfHolder <- imgH2 } } + +func GetPNGGraph(GraphID, start, end string) (png string, err error) { + //请求图形 + ZabbixWeb := GetConfKey("zabbix_web") + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client1 := &http.Client{tr, nil, + JAR, 99999999999992} + imgurl := ZabbixWeb + "/chart2.php?" + data := url.Values{} + URL, err := url.Parse(imgurl) + if err != nil { + logs.Error(err) + return "", err + } + data.Set("graphid", GraphID) + data.Set("from", start) + data.Set("to", end) + data.Set("profileIdx", "web.graphs.filter") + //data.Set("profileIdx2", "200") + data.Set("high", "200") + data.Set("width", "800") + //不显示图形名称 + data.Set("widget_view", "1") + data.Set("resolve_macros", "1") + //Encode rul + URL.RawQuery = data.Encode() + urlPath := URL.String() + request, err := http.NewRequest("GET", urlPath, nil) + if err != nil { + logs.Error(err) + return "", err + } + request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") + request.Header.Add("Accept-Encoding", "gzip, deflate") + request.Header.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3") + request.Header.Add("Connection", "keep-alive") + request.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0") + response1, err := client1.Do(request) + if err != nil { + logs.Error(err) + return "", err + } + defer response1.Body.Close() + if response1.StatusCode == 200 { + var reader io.Reader + switch response1.Header.Get("Content-Encoding") { + case "gzip": + reader, _ = gzip.NewReader(response1.Body) + default: + reader = response1.Body + } + body, err := io.ReadAll(reader) + if err != nil { + return "", err + } + res := base64.StdEncoding.EncodeToString(body) + return res, nil + } + return "", err +} diff --git a/models/index.go b/models/index.go index bf9b949..baea054 100644 --- a/models/index.go +++ b/models/index.go @@ -35,6 +35,8 @@ func GetRouter(username string) ([]RouterRes, error) { {Router: "server", Path: "server", Name: "硬件管理", Icon: "database", Meta: Meta{Page: Page{CacheAble: false}}, Children: []TRouterChildren{ {Name: "物理服务器", Router: "srvList", Path: "list", Icon: "mobile"}, + {Name: "光纤交换机", Router: "sanList", Path: "fiber", Icon: "mobile"}, + {Name: "存储设备", Router: "stoList", Path: "storage", Icon: "mobile"}, {Name: "设备详情", Router: "srvDetail", Path: "detail", Meta: Meta{Highlight: "/server", Invisible: true}}, }}, {Router: "alarm", Path: "alarm", Name: "告警管理", Icon: "alert", Meta: Meta{Page: Page{CacheAble: false}}, @@ -260,14 +262,13 @@ func GetOverviewData() (OverviewList, error) { var ArrayOne []Hosts p, err := RDB.Get(ctx, v+"_OVERVIEW").Result() if err != nil { - return OverviewList{}, err logs.Error(err) continue } err = json.Unmarshal([]byte(p), &ArrayOne) if err != nil { logs.Error(err) - return OverviewList{}, err + continue } listmap[v] = ArrayOne } diff --git a/models/item.go b/models/item.go index e3f9bdb..0fd10c6 100644 --- a/models/item.go +++ b/models/item.go @@ -7,7 +7,7 @@ import ( "time" ) -//GetItemByKey bye key +// GetItemByKey bye key func GetItemByKey(hostid, key string) (item []Item, err error) { par := make(map[string]string) par["key_"] = key @@ -33,7 +33,7 @@ func GetItemByKey(hostid, key string) (item []Item, err error) { return hb, err } -//GetAllItemByHostID func +// GetAllItemByHostID func func GetAllItemByHostID(hostid string) (item []Item, count int64, err error) { output := []string{"itemid", "name", "key_", "value_type", "units", "hostid"} rep, err := API.Call("item.get", Params{"output": output, "sortfield": "name", @@ -58,14 +58,14 @@ func GetAllItemByHostID(hostid string) (item []Item, count int64, err error) { return hb, int64(len(hb)), err } -//GetAllItemByHostID func +// GetAllItemByHostID func func GetAllTrafficeItemByHostID(hostid string) (item []interface{}, count int64, err error) { var ItemList []interface{} if ZBX_V { ItemsOutput := []string{"itemid", "tags", "value_type", "name", "key_", "delay", "units", "lastvalue", "lastclock"} selectTags := []string{"tag", "value"} Search2Par := make(map[string]string, 1) - Search2Par["tag"] = "interface" + Search2Par["tag"] = "Interface" Search2Par["value"] = "" Par := make(map[int]interface{}) Par[0] = Search2Par @@ -89,7 +89,7 @@ func GetAllTrafficeItemByHostID(hostid string) (item []interface{}, count int64, } for _, v := range ts { for _, vv := range v.Tags { - if vv.Tag == "interface" { + if vv.Tag == "Interface" { switch { case strings.Contains(v.Name, "Bits received"): ItemList = append(ItemList, v) @@ -132,7 +132,7 @@ func GetAllTrafficeItemByHostID(hostid string) (item []interface{}, count int64, return ItemList, int64(len(ItemList)), nil } -//GetAllItemByHostID func +// GetAllItemByHostID func func GetReceiveTrafficeItemByHostID(hostid string) (item []interface{}, count int64, err error) { var ItemList []interface{} if ZBX_V { @@ -206,7 +206,7 @@ func GetReceiveTrafficeItemByHostID(hostid string) (item []interface{}, count in return ItemList, int64(len(ItemList)), nil } -//GetFlowItemByHostID func +// GetFlowItemByHostID func func GetFlowItemByHostID(hostid string) (item []Item, count int64, err error) { output := []string{"itemid", "name", "key_", "value_type", "units"} rep, err := API.Call("item.get", Params{"output": output, "" + @@ -233,7 +233,7 @@ func GetFlowItemByHostID(hostid string) (item []Item, count int64, err error) { return hb, int64(len(hb)), err } -//GetAllItemByHostID func +// GetAllItemByHostID func func GetItemByID(itemid string) (item []Item, err error) { if itemid == "" { return []Item{}, err @@ -260,7 +260,7 @@ func GetItemByID(itemid string) (item []Item, err error) { return hb, err } -//GetValueMap +// GetValueMap func GetValueMapByID(id, value string) (newvalue string, err error) { if id == "" { return "", err @@ -304,7 +304,7 @@ func GetValueMapByID(id, value string) (newvalue string, err error) { } -//GetItemByItemids +// GetItemByItemids func GetItemByIDS(itemids []string) (item []Item, err error) { if len(itemids) == 0 { return []Item{}, err diff --git a/models/report.go b/models/report.go index 318f043..043c970 100644 --- a/models/report.go +++ b/models/report.go @@ -10,12 +10,12 @@ import ( "zbxtable/utils" ) -//TableName alarm +// TableName alarm func (t *Report) TableName() string { return TableName("report") } -//get id +// GetReportsByID f func GetReportsByID(id int) (v *Report, err error) { o := orm.NewOrm() v = &Report{ID: id} @@ -25,7 +25,7 @@ func GetReportsByID(id int) (v *Report, err error) { return nil, err } -//get all +// get all func GetALlReport() (cnt int64, system []Report, err error) { o := orm.NewOrm() var sys []Report diff --git a/models/rule.go b/models/rule.go index ac1e009..2b79b8d 100644 --- a/models/rule.go +++ b/models/rule.go @@ -126,7 +126,7 @@ func UpdateRule(m *Rule, tuser string) error { m.UserIds = utils.VAarToStr(m.UserIds) m.GroupIds = utils.VAarToStr(m.GroupIds) _, err = o.Update(m, "name", "tenant_id", "conditions", "s_week", "m_type", - "s_time", "e_time", "channel", "user_ids", "group_ids", "note", "status", "status") + "s_time", "e_time", "channel", "user_ids", "group_ids", "note", "status") if err != nil { return err } diff --git a/models/session.go b/models/session.go index 510ba14..b44a18b 100644 --- a/models/session.go +++ b/models/session.go @@ -6,32 +6,31 @@ import ( "github.com/astaxie/beego" "github.com/astaxie/beego/logs" "io" - "io/ioutil" "net/http" "net/url" "os" "strings" ) -//Jar struct +// Jar struct type Jar struct { cookies []*http.Cookie } -//SetCookies a +// SetCookies a func (jar *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) { jar.cookies = cookies } -//Cookies func +// Cookies func func (jar *Jar) Cookies(u *url.URL) []*http.Cookie { return jar.cookies } -//JAR st +// JAR st var JAR = new(Jar) -//LoginZabbixWeb a +// LoginZabbixWeb a func LoginZabbixWeb(ZabbixWeb, ZabbixUser, ZabbixPass string) { v := url.Values{} v.Set("name", ZabbixUser) @@ -43,26 +42,23 @@ func LoginZabbixWeb(ZabbixWeb, ZabbixUser, ZabbixPass string) { } client := &http.Client{ tr, nil, JAR, 99999999999999} - reqest, err := http.NewRequest("POST", ZabbixWeb+"/index.php", strings.NewReader(v.Encode())) + request, err := http.NewRequest("POST", ZabbixWeb+"/index.php", strings.NewReader(v.Encode())) if err != nil { logs.Error("Fatal error ", err.Error()) return } - reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") - reqest.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") - reqest.Header.Add("Accept-Encoding", "gzip, deflate") - reqest.Header.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3") - reqest.Header.Add("Connection", "keep-alive") - reqest.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0") - response, err := client.Do(reqest) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") + request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") + request.Header.Add("Accept-Encoding", "gzip, deflate") + request.Header.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3") + request.Header.Add("Connection", "keep-alive") + request.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0") + response, err := client.Do(request) if err != nil { logs.Error("Fatal error ", err.Error()) return } defer response.Body.Close() - if beego.BConfig.RunMode == "dev" { - logs.Info("Login to zabbix successfully!http status code:", response.StatusCode) - } if response.StatusCode == 200 { var reader io.Reader switch response.Header.Get("Content-Encoding") { @@ -71,16 +67,23 @@ func LoginZabbixWeb(ZabbixWeb, ZabbixUser, ZabbixPass string) { default: reader = response.Body } - data, err := ioutil.ReadAll(reader) + data, err := io.ReadAll(reader) if err != nil { logs.Error("Failed to read response data: %+v", err) } - //if beego.BConfig.RunMode == "dev" { - // logs.Info("Login to zabbix response body is:", string(data)) - //} - if !strings.Contains(string(data), "Dashboard") { + if beego.BConfig.RunMode == "dev" { + logs.Info("Login to zabbix response body is:", string(data)) + } + if strings.Contains(string(data), "blocked") { logs.Error("Login to Zabbix failed!") os.Exit(1) } + } else { + os.Exit(1) + } + if beego.BConfig.RunMode == "dev" { + logs.Info("Login to zabbix successfully!http status code:", response.StatusCode) + } else { + logs.Info("Login to zabbix successfully!") } } diff --git a/routers/commentsRouter____controllers.go b/routers/commentsRouter____controllers.go index a99b5e8..fc71e35 100644 --- a/routers/commentsRouter____controllers.go +++ b/routers/commentsRouter____controllers.go @@ -250,6 +250,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["zbxtable/controllers:HostController"] = append(beego.GlobalControllerRouter["zbxtable/controllers:HostController"], + beego.ControllerComments{ + Method: "GetGraph", + Router: "/graph/:hostid", + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["zbxtable/controllers:HostController"] = append(beego.GlobalControllerRouter["zbxtable/controllers:HostController"], beego.ControllerComments{ Method: "GetMonInterface",