diff --git a/ChangeLog.md b/ChangeLog.md index 4054b41..688495b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,13 @@ +# Changelog # +## 4.2.0 ## +#### 新功能 #### +1. 现在支持通过 ecmc/n9e 来获取监控的 ip 列表,无需手动配置配置文件了,详见 [README](https://github.com/gaochao1/swcollector/blob/master/README.md}) + +# Changelog # +## 4.1.0 ## +#### 新功能 #### +1. 现在支持推送数据到 n9e 了 + # Changelog # ## 4.0.6.3 ## #### bug修复 #### diff --git a/README.md b/README.md index 05b182a..5943214 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,19 @@ swcollector需要部署到有交换机SNMP访问权限的服务器上。 "limitConcur": 1000, #交换机采集的并发限制 "limitCon": 4 #对于单台交换机上,多个指标采集的并发限制 }, + "ecmc":{ # 从 ecmc,即夜莺的商业版上获取待监控的 ip 列表,此时 switch 中配置的 ipRange 会被忽略,当 ecmc 和 n9e 同时配置时,ecmc 优先,n9e 的配置忽略 + "enabled":false, # true 即开启 + "addr":"http://ecmc.example.com", # ecmc 的地址 + "token":"x-user-token", # ecmc 供 api 调用的 token,在个人设置-密钥管理中配置 + "nodes":[1,2,3,4] # 监控 ip 所在的 node id 列表,鼠标点在 node 上能看到节点 id + }, + "n9e":{ # 从 n9e ,即夜莺的开源版上获取待监控的 ip 列表,此时 switch 中配置的 ipRange 会被忽略。 + "enabled":true, # true 即开启 + "addr":"http://n9e.example.com", # n9e 的地址 + "user":"root", # 用户名 + "pass":"1234", # 密码 + "nodes":[1,2,3,4] # 监控 ip 所在的 node id 列表,可以先通过 curl -u root:1234 http://n9e.example.com/api/portal/tree 看下自己节点的 id 号 + }, "switchhosts":{ "enabled":false, "hosts":"./hosts.json" #自定义的host与Ip地址对应表,如果配置,则上报时会用这里的host替换ip地址 diff --git a/cfg.example.json b/cfg.example.json index e0a88cf..45630da 100644 --- a/cfg.example.json +++ b/cfg.example.json @@ -37,7 +37,20 @@ "fastPingMode": true, "limitConcur": 1000, "limitCon": 4 - }, + }, + "ecmc":{ + "enabled":false, + "addr":"http://ecmc.example.com", + "token":"x-user-token", + "nodes":[1,2,3,4] + }, + "n9e":{ + "enabled":true, + "addr":"http://n9e.example.com", + "user":"root", + "pass":"1234", + "nodes":[1,2,3,4] + }, "switchhosts":{ "enabled":false, "hosts":"./hosts.json" diff --git a/funcs/ecmc.go b/funcs/ecmc.go new file mode 100644 index 0000000..efb2a90 --- /dev/null +++ b/funcs/ecmc.go @@ -0,0 +1,131 @@ +package funcs + +import ( + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "net/http" + "time" + + "github.com/gaochao1/swcollector/g" +) + +type EcmcRes struct { + Dat json.RawMessage `json:"dat"` + Err string `json:"err"` +} + +type Host struct { + ID int64 `json:"id"` + SN string `json:"sn"` + IP string `json:"ip"` + Name string `json:"name"` + Note string `json:"note"` + Cpu string `json:"cpu"` + Mem string `json:"mem"` + Disk string `json:"disk"` + Cate string `json:"cate"` + Tenant string `json:"tenant"` +} + +type n9eHost struct { + ID int64 `json:"id"` + Ident string `json:"ident"` + Alias string `json:"alias"` +} + +type NodeHosts struct { + List []Host `json:"list"` + Total int64 `json:"total"` +} + +// HTTPGet 发起一个 http get 请求 +func HTTPGet(url string, headers map[string]string) (body []byte, err error) { + body = []byte{} + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return + } + for k, v := range headers { + req.Header.Set(k, v) + } + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{ + Transport: tr, + Timeout: 15 * time.Second, + } + resp, err := client.Do(req) + if err != nil { + return + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + body, _ = ioutil.ReadAll(resp.Body) + erroMsg := fmt.Sprintf("HTTP Connect Failed, Code is %d, body is %s", resp.StatusCode, string(body)) + err = errors.New(erroMsg) + return + } + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + return + } + return +} + +func GetNodeHosts(nodeID int64) (hosts []Host, err error) { + p := 1 + for { + apiAddr := fmt.Sprintf("%s/api/hsp/node/obj/%d/host?p=%d", g.Config().Ecmc.Addr, nodeID, p) + headers := map[string]string{} + headers["x-user-token"] = g.Config().Ecmc.Token + var res []byte + res, err = HTTPGet(apiAddr, headers) + if err != nil { + return + } + var ecmcRes EcmcRes + if err = json.Unmarshal(res, &ecmcRes); err != nil { + return + } + if ecmcRes.Err != "" { + err = errors.New(ecmcRes.Err) + return + } + var nodeHosts NodeHosts + if err = json.Unmarshal(ecmcRes.Dat, &nodeHosts); err != nil { + return + } + if len(nodeHosts.List) == 0 { + break + } + hosts = append(hosts, nodeHosts.List...) + p = p + 1 + } + return +} + +func GetAllByIpByEcmc() (ips []string) { + ipMap := map[string]bool{} + for _, id := range g.Config().Ecmc.Nodes { + hosts, err := GetNodeHosts(id) + if err != nil { + log.Println(err) + continue + } + for _, host := range hosts { + if _, ok := ipMap[host.IP]; ok { + continue + } + ipMap[host.IP] = true + ips = append(ips, host.IP) + } + } + return +} diff --git a/funcs/n9e.go b/funcs/n9e.go new file mode 100644 index 0000000..a3cb8ef --- /dev/null +++ b/funcs/n9e.go @@ -0,0 +1,79 @@ +package funcs + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + + "log" + + "github.com/gaochao1/swcollector/g" +) + +type N9eNodeHosts struct { + List []N9eHost `json:"list"` + Total int64 `json:"total"` +} + +type N9eHost struct { + ID int64 `json:"id"` + IP string `json:"ident"` + Alias string `json:"alias"` +} + +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} + +func GetN9eHosts(nodeID int64) (hosts []N9eHost, err error) { + p := 1 + for { + apiAddr := fmt.Sprintf("%s/api/portal/node/%d/endpoint?p=%d", g.Config().N9e.Addr, nodeID, p) + headers := map[string]string{} + headers["Authorization"] = "Basic " + basicAuth(g.Config().N9e.User, g.Config().N9e.Pass) + var res []byte + res, err = HTTPGet(apiAddr, headers) + if err != nil { + return + } + var ecmcRes EcmcRes + if err = json.Unmarshal(res, &ecmcRes); err != nil { + return + } + if ecmcRes.Err != "" { + err = errors.New(ecmcRes.Err) + return + } + var nodeHosts N9eNodeHosts + if err = json.Unmarshal(ecmcRes.Dat, &nodeHosts); err != nil { + return + } + if len(nodeHosts.List) == 0 { + break + } + hosts = append(hosts, nodeHosts.List...) + p = p + 1 + } + return +} + +func GetAllByIpByN9e() (ips []string) { + ipMap := map[string]bool{} + for _, id := range g.Config().N9e.Nodes { + hosts, err := GetN9eHosts(id) + if err != nil { + log.Println(err) + continue + } + for _, host := range hosts { + if _, ok := ipMap[host.IP]; ok { + continue + } + ipMap[host.IP] = true + ips = append(ips, host.IP) + } + } + return +} diff --git a/funcs/swifstat.go b/funcs/swifstat.go index b6b4960..17d4a80 100644 --- a/funcs/swifstat.go +++ b/funcs/swifstat.go @@ -104,7 +104,7 @@ func initVariable() { ignoreOutQLen = g.Config().Switch.IgnoreOutQLen } -func AllSwitchIp() (allIp []string) { +func GetAllByIpRange() (allIp []string) { switchIp := g.Config().Switch.IpRange if len(switchIp) > 0 { @@ -118,6 +118,19 @@ func AllSwitchIp() (allIp []string) { return allIp } +func AllSwitchIp() (allIp []string) { + if g.Config().Ecmc.Enabled { + allIp = GetAllByIpByEcmc() + return allIp + } + if g.Config().N9e.Enabled { + allIp = GetAllByIpByN9e() + return allIp + } + allIp = GetAllByIpRange() + return allIp +} + func SwIfMetrics() (L []*model.MetricValue) { if g.Config().Switch.Enabled && len(g.Config().Switch.IpRange) > 0 { return swIfMetrics() diff --git a/g/cfg.go b/g/cfg.go index 464c0aa..be57ae9 100644 --- a/g/cfg.go +++ b/g/cfg.go @@ -73,10 +73,27 @@ type CustomMetricsConfig struct { Template string `json:template` } +type EcmcConfig struct { + Enabled bool `json:"enabled"` + Addr string `json:"addr"` + Token string `json:"token"` + Nodes []int64 `json:"nodes"` +} + +type N9eConfig struct { + Enabled bool `json:"enabled"` + Addr string `json:"addr"` + User string `json:"user"` + Pass string `json:"pass"` + Nodes []int64 `json:"nodes"` +} + type GlobalConfig struct { Debug bool `json:"debug"` Debugmetric *DebugmetricConfig `json:"debugmetric` Switch *SwitchConfig `json:"switch"` + Ecmc EcmcConfig `json:"ecmc"` + N9e N9eConfig `json:"n9e"` Transfer *TransferConfig `json:"transfer"` SwitchHosts *SwitchHostsConfig `json:switchhosts` CustomMetrics *CustomMetricsConfig `json:customMetrics` diff --git a/g/const.go b/g/const.go index 75854c1..d5c4a49 100644 --- a/g/const.go +++ b/g/const.go @@ -23,7 +23,8 @@ import ( // 4.0.6.3 fix bugs // 4.1.0 support n9e transfer mode // 4.1.1 n9e mode support debug +// 4.2.0 support get allip from ecmc nodes const ( - VERSION = "4.1.3" + VERSION = "4.2.0" COLLECT_INTERVAL = time.Second )