diff options
author | Andris Zeila <andris.zeila@zabbix.com> | 2022-02-17 11:28:39 +0300 |
---|---|---|
committer | Andris Zeila <andris.zeila@zabbix.com> | 2022-02-17 11:28:39 +0300 |
commit | 6f2d97e4bd0bb5b22ce41857967f742d7e98860b (patch) | |
tree | a60d975ac564c473c0bba3bec7b9342aa4fb910b /src | |
parent | fbe2982527dd41559cb411377d7b09dc63cce57d (diff) | |
parent | 538e9fe6e864b0fedd51cbbf5761f1f7a26df699 (diff) |
.......... [ZBX-20487] merged branch 'release/5.4' of ssh://git.zabbix.lan:7999/zbx/zabbix into feature/ZBX-20487-5.4
Diffstat (limited to 'src')
27 files changed, 1230 insertions, 299 deletions
diff --git a/src/go/go.mod b/src/go/go.mod index 5add1054209..567ebe9a064 100644 --- a/src/go/go.mod +++ b/src/go/go.mod @@ -20,10 +20,11 @@ require ( github.com/mattn/go-sqlite3 v1.14.8 github.com/mediocregopher/radix/v3 v3.5.0 github.com/memcachier/mc/v3 v3.0.1 + github.com/miekg/dns v1.1.43 github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce github.com/omeid/go-yarn v0.0.1 github.com/pkg/errors v0.9.1 // indirect - golang.org/x/sys v0.0.0-20210104204734-6f8348627aad + golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 diff --git a/src/go/go.sum b/src/go/go.sum index 9837d44acc3..7267d198195 100644 --- a/src/go/go.sum +++ b/src/go/go.sum @@ -134,6 +134,8 @@ github.com/mediocregopher/radix/v3 v3.5.0 h1:8QHQmNh2ne9aFxTD3z63u/bkPPiOtknHoz8 github.com/mediocregopher/radix/v3 v3.5.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/memcachier/mc/v3 v3.0.1 h1:Os/fUl/8c+hc1qWgjv5hNK0JI6GxKUOuehzB/UmjLP0= github.com/memcachier/mc/v3 v3.0.1/go.mod h1:GzjocBahcXPxt2cmqzknrgqCOmMxiSzhVKPOe90Tpug= +github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce h1:TqjP/BTDrwN7zP9xyXVuLsMBXYMt6LLYi55PlrIcq8U= github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:ifHPsLndGGzvgzcaXUvzmt6LxKT4pJ+uzEhtnMt+f7A= github.com/omeid/go-yarn v0.0.1 h1:mUQExNwUrYn7tZRwQdsUuoQWHIujtjjpjb/PAtUj9dk= @@ -185,9 +187,12 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -201,6 +206,10 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad h1:MCsdmFSdEd4UEa5TKS5JztCRHK/WtvNei1edOj5RSRo= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 h1:cEhElsAv9LUt9ZUUocxzWe05oFLVd+AA2nstydTeI8g= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= diff --git a/src/go/internal/agent/resultcache/diskcache.go b/src/go/internal/agent/resultcache/diskcache.go index fc8b4e112d6..607c7c41db3 100644 --- a/src/go/internal/agent/resultcache/diskcache.go +++ b/src/go/internal/agent/resultcache/diskcache.go @@ -22,6 +22,7 @@ import ( "database/sql" "encoding/json" "fmt" + "sync" "sync/atomic" "time" @@ -41,6 +42,10 @@ const ( DataLimit = 10000 ) +var ( + cacheLock sync.Mutex +) + type DiskCache struct { *cacheData storagePeriod int64 @@ -153,36 +158,29 @@ func (c *DiskCache) updateLogRange() (err error) { return } -func (c *DiskCache) upload(u Uploader) (err error) { - var results []*AgentData +func (c *DiskCache) resultsGet() (results []*AgentData, maxDataId uint64, maxLogId uint64, err error) { var result *AgentData var rows *sql.Rows - var maxDataId, maxLogId uint64 + + cacheLock.Lock() + defer cacheLock.Unlock() if rows, err = c.database.Query(fmt.Sprintf("SELECT "+ "id,itemid,lastlogsize,mtime,state,value,eventsource,eventid,eventseverity,eventtimestamp,clock,ns"+ " FROM data_%d ORDER BY id LIMIT ?", c.serverID), DataLimit); err != nil { c.Errf("cannot select from data table: %s", err.Error()) - return + return nil, 0, 0, err } - - defer func() { - if err != nil && (c.lastError == nil || err.Error() != c.lastError.Error()) { - c.Warningf("cannot upload history data: %s", err) - c.lastError = err - } - }() - for rows.Next() { if result, err = c.resultFetch(rows); err != nil { rows.Close() - return + return nil, 0, 0, err } result.persistent = false results = append(results, result) } if err = rows.Err(); err != nil { - return + return nil, 0, 0, err } dataLen := len(results) if dataLen != 0 { @@ -192,29 +190,44 @@ func (c *DiskCache) upload(u Uploader) (err error) { if dataLen != DataLimit { if rows, err = c.database.Query(fmt.Sprintf("SELECT "+ "id,itemid,lastlogsize,mtime,state,value,eventsource,eventid,eventseverity,eventtimestamp,clock,ns"+ - " FROM log_%d ORDER BY id LIMIT ?", c.serverID), - DataLimit-len(results)); err != nil { - + " FROM log_%d ORDER BY id LIMIT ?", c.serverID), DataLimit-len(results)); err != nil { c.Errf("cannot select from log table: %s", err.Error()) - return + return nil, 0, 0, err } - for rows.Next() { if result, err = c.resultFetch(rows); err != nil { rows.Close() - return + return nil, 0, 0, err } result.persistent = true results = append(results, result) } if err = rows.Err(); err != nil { - return + return nil, 0, 0, err } if len(results) != dataLen { maxLogId = results[len(results)-1].Id } } + return results, maxDataId, maxLogId, nil +} + +func (c *DiskCache) upload(u Uploader) (err error) { + var results []*AgentData + var maxDataId, maxLogId uint64 + + defer func() { + if err != nil && (c.lastError == nil || err.Error() != c.lastError.Error()) { + c.Warningf("cannot upload history data: %s", err) + c.lastError = err + } + }() + + if results, maxDataId, maxLogId, err = c.resultsGet(); err != nil { + return + } + if len(results) == 0 { return } @@ -250,6 +263,8 @@ func (c *DiskCache) upload(u Uploader) (err error) { c.Warningf("history upload to [%s %s] is working again", u.Addr(), u.Hostname()) c.lastError = nil } + cacheLock.Lock() + defer cacheLock.Unlock() if maxDataId != 0 { if _, err = c.database.Exec(fmt.Sprintf("DELETE FROM data_%d WHERE id<=?", c.serverID), maxDataId); err != nil { return fmt.Errorf("cannot delete from data_%d: %s", c.serverID, err) @@ -334,7 +349,11 @@ func (c *DiskCache) write(r *plugin.Result) { var stmt *sql.Stmt now := time.Now().Unix() + cacheLock.Lock() + defer cacheLock.Unlock() + if r.Persistent { + if c.oldestLog == 0 { c.oldestLog = clock } @@ -359,6 +378,7 @@ func (c *DiskCache) write(r *plugin.Result) { if _, err = c.database.Exec(query, now-c.storagePeriod); err != nil { c.Errf("cannot delete old data from data_%d : %s", c.serverID, err) } + c.oldestData, err = c.getOldestWriteClock(tableName("data", c.serverID)) if err != nil { c.Errf("cannot query minimum write clock from data_%d : %s", c.serverID, err) @@ -426,6 +446,9 @@ func (c *DiskCache) init(options *agent.AgentOptions) { c.updateOptions(options) var err error + cacheLock.Lock() + defer cacheLock.Unlock() + c.database, err = sql.Open("sqlite3", agent.Options.PersistentBufferFile) if err != nil { return diff --git a/src/go/pkg/version/version.go b/src/go/pkg/version/version.go index aa618304ebc..b219bfd722a 100644 --- a/src/go/pkg/version/version.go +++ b/src/go/pkg/version/version.go @@ -26,10 +26,10 @@ import ( ) const ( - ZABBIX_REVDATE = "25 January 2022" + ZABBIX_REVDATE = "31 January 2022" ZABBIX_VERSION_MAJOR = 5 ZABBIX_VERSION_MINOR = 4 - ZABBIX_VERSION_PATCH = 10 + ZABBIX_VERSION_PATCH = 11 ZABBIX_VERSION_RC = "rc1" ZABBIX_VERSION_RC_NUM = "{ZABBIX_RC_NUM}" ZABBIX_VERSION_REVISION = "{ZABBIX_REVISION}" diff --git a/src/go/pkg/zbxlib/checks_darwin.go b/src/go/pkg/zbxlib/checks_darwin.go index 83e7d8ac546..52b69a7f060 100644 --- a/src/go/pkg/zbxlib/checks_darwin.go +++ b/src/go/pkg/zbxlib/checks_darwin.go @@ -31,8 +31,6 @@ package zbxlib #include "sysinfo.h" int SYSTEM_LOCALTIME(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result); int SYSTEM_BOOTTIME(AGENT_REQUEST *request, AGENT_RESULT *result); int NET_TCP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result); int NET_TCP_PORT(AGENT_REQUEST *request, AGENT_RESULT *result); @@ -58,10 +56,6 @@ func resolveMetric(key string) (cfunc unsafe.Pointer) { switch key { case "system.localtime": return unsafe.Pointer(C.SYSTEM_LOCALTIME) - case "net.dns": - return unsafe.Pointer(C.NET_DNS) - case "net.dns.record": - return unsafe.Pointer(C.NET_DNS_RECORD) case "system.boottime": return unsafe.Pointer(C.SYSTEM_BOOTTIME) case "net.tcp.listen": diff --git a/src/go/pkg/zbxlib/checks_linux.go b/src/go/pkg/zbxlib/checks_linux.go index ed77a2c7fd9..b1ee05ce6a4 100644 --- a/src/go/pkg/zbxlib/checks_linux.go +++ b/src/go/pkg/zbxlib/checks_linux.go @@ -29,8 +29,6 @@ package zbxlib #include "module.h" int SYSTEM_LOCALTIME(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result); int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result); int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result); int SYSTEM_BOOTTIME(AGENT_REQUEST *request, AGENT_RESULT *result); @@ -66,10 +64,6 @@ func resolveMetric(key string) (cfunc unsafe.Pointer) { switch key { case "system.localtime": cfunc = unsafe.Pointer(C.SYSTEM_LOCALTIME) - case "net.dns": - cfunc = unsafe.Pointer(C.NET_DNS) - case "net.dns.record": - cfunc = unsafe.Pointer(C.NET_DNS_RECORD) case "system.boottime": cfunc = unsafe.Pointer(C.SYSTEM_BOOTTIME) case "net.tcp.listen": diff --git a/src/go/pkg/zbxlib/checks_windows.go b/src/go/pkg/zbxlib/checks_windows.go index 0bbb90ed1c9..7fc54510f98 100644 --- a/src/go/pkg/zbxlib/checks_windows.go +++ b/src/go/pkg/zbxlib/checks_windows.go @@ -29,8 +29,6 @@ package zbxlib #include "module.h" int SYSTEM_LOCALTIME(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result); -int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result); int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result); int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result); int SYSTEM_BOOTTIME(AGENT_REQUEST *request, AGENT_RESULT *result); @@ -64,10 +62,6 @@ func resolveMetric(key string) (cfunc unsafe.Pointer) { switch key { case "system.localtime": cfunc = unsafe.Pointer(C.SYSTEM_LOCALTIME) - case "net.dns": - cfunc = unsafe.Pointer(C.NET_DNS) - case "net.dns.record": - cfunc = unsafe.Pointer(C.NET_DNS_RECORD) } return diff --git a/src/go/plugins/net/dns/dns.go b/src/go/plugins/net/dns/dns.go new file mode 100644 index 00000000000..306b842adc0 --- /dev/null +++ b/src/go/plugins/net/dns/dns.go @@ -0,0 +1,502 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +package dns + +import ( + "fmt" + "net" + "strconv" + "strings" + "time" + + "github.com/miekg/dns" + "zabbix.com/pkg/plugin" + "zabbix.com/pkg/zbxerr" +) + +const ( + base10 = 10 + + tcpProtocol = "tcp" + udpProtocol = "udp" +) + +const ( + noneParam = iota + firstParam + secondParam + thirdParam + fourthParam + fifthParam + sixthParam +) + +type options struct { + ip string + name string + protocol string + dnsType uint16 + count int + timeout time.Duration +} + +// Plugin - +type Plugin struct { + plugin.Base +} + +var impl Plugin + +var dnsTypes = map[string]uint16{ + "ANY": dns.TypeANY, + "A": dns.TypeA, + "NS": dns.TypeNS, + "CNAME": dns.TypeCNAME, + "MB": dns.TypeMB, + "MG": dns.TypeMG, + "MR": dns.TypeMR, + "PTR": dns.TypePTR, + "MD": dns.TypeMD, + "MF": dns.TypeMF, + "MX": dns.TypeMX, + "SOA": dns.TypeSOA, + "NULL": dns.TypeNULL, + "HINFO": dns.TypeHINFO, + "MINFO": dns.TypeMINFO, + "TXT": dns.TypeTXT, + "AAAA": dns.TypeAAAA, + "SRV": dns.TypeSRV, +} + +// Export - +func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) { + switch key { + case "net.dns": + return exportDns(params) + case "net.dns.record": + return exportDnsRecord(params) + default: + err = zbxerr.ErrorUnsupportedMetric + + return + } +} + +func exportDns(params []string) (result interface{}, err error) { + answer, err := getDNSAnswers(params) + if err != nil { + return + } + + if len(answer) < 1 { + return 0, nil + } + + return 1, nil +} + +func exportDnsRecord(params []string) (result interface{}, err error) { + answer, err := getDNSAnswers(params) + if err != nil { + return + } + + if len(answer) < 1 { + return nil, zbxerr.New("Cannot perform DNS query.") + } + + return parseAnswers(answer), nil +} + +func parseAnswers(answers []dns.RR) string { + var out string + answersNum := len(answers) + for i, a := range answers { + out += fmt.Sprintf("%-20s", strings.TrimSuffix(a.Header().Name, ".")) + out += fmt.Sprintf(" %-8s ", dns.Type(a.Header().Rrtype).String()) + + switch rr := a.(type) { + case *dns.A: + out += getAString(rr) + case *dns.NS: + out += getNSString(rr) + case *dns.CNAME: + out += getCNAMEString(rr) + case *dns.MB: + out += getMBString(rr) + case *dns.MG: + out += getMGString(rr) + case *dns.PTR: + out += getPTRString(rr) + case *dns.MD: + out += getMDString(rr) + case *dns.MF: + out += getMFString(rr) + case *dns.MX: + out += getMXString(rr) + case *dns.SOA: + out += getSOAString(rr) + case *dns.NULL: + out += getNULLString(rr) + case *dns.HINFO: + out += getHINFOString(rr) + case *dns.MINFO: + out += getMINFOString(rr) + case *dns.TXT: + out += getTXTString(rr) + case *dns.AAAA: + out += getAAAAString(rr) + case *dns.SRV: + out += getSRVString(rr) + } + + if i != answersNum - 1 { + out += "\n" + } + } + + return out +} + +func getDNSAnswers(params []string) ([]dns.RR, error) { + options, err := parseParamas(params) + if err != nil { + return nil, err + } + + var resp *dns.Msg + for i := 1; i <= options.count; i++ { + resp, err = runQuery(options.ip, options.name, options.protocol, options.dnsType, options.timeout) + if err != nil { + continue + } + + break + } + + if err != nil { + return nil, zbxerr.ErrorCannotFetchData.Wrap(err) + } + + return resp.Answer, nil +} + +func getSOAString(in *dns.SOA) string { + return strings.TrimSuffix(in.Ns, ".") + + " " + strings.TrimSuffix(in.Mbox, ".") + + " " + strconv.FormatInt(int64(in.Serial), base10) + + " " + strconv.FormatInt(int64(in.Refresh), base10) + + " " + strconv.FormatInt(int64(in.Retry), base10) + + " " + strconv.FormatInt(int64(in.Expire), base10) + + " " + strconv.FormatInt(int64(in.Minttl), base10) +} + +func getAString(in *dns.A) string { + if in.A == nil { + return "\n" + } + + return in.A.String() +} + +func getNSString(in *dns.NS) string { + return strings.TrimSuffix(in.Ns, ".") +} + +func getCNAMEString(in *dns.CNAME) string { + return strings.TrimSuffix(in.Target, ".") +} + +func getMBString(in *dns.MB) string { + return strings.TrimSuffix(in.Mb, ".") +} + +func getMGString(in *dns.MG) string { + return strings.TrimSuffix(in.Mg, ".") +} + +func getPTRString(in *dns.PTR) string { + return strings.TrimSuffix(in.Ptr, ".") +} + +func getMDString(in *dns.MD) string { + return strings.TrimSuffix(in.Md, ".") +} + +func getMFString(in *dns.MF) string { + return strings.TrimSuffix(in.Mf, ".") +} + +func getMXString(in *dns.MX) string { + return strconv.Itoa(int(in.Preference)) + + " " + strings.TrimSuffix(in.Mx, ".") +} + +func getNULLString(in *dns.NULL) string { + return strings.TrimSuffix(in.Data, ".") +} + +func getHINFOString(in *dns.HINFO) string { + return parseTXT(in.Cpu, in.Os) + +} + +func getMINFOString(in *dns.MINFO) string { + return strings.TrimSuffix(in.Rmail, ".") + " " + + strings.TrimSuffix(in.Email, ".") +} + +func getTXTString(in *dns.TXT) string { + return parseTXT(in.Txt...) +} + +func getAAAAString(in *dns.AAAA) string { + if in.AAAA == nil { + return "\n" + } + + return in.AAAA.String() +} + +func getSRVString(in *dns.SRV) string { + return strconv.Itoa(int(in.Priority)) + " " + + strconv.Itoa(int(in.Weight)) + " " + + strconv.Itoa(int(in.Port)) + " " + + strings.TrimSuffix(in.Target, ".") +} + +func parseTXT(in ...string) string { + var out string + for _, s := range in { + if s != "" { + out += "\"" + s + "\"" + " " + } + } + + return strings.TrimSpace(out) +} + +func parseParamas(params []string) (o options, err error) { + switch len(params) { + case sixthParam: + err = o.setProtocol(params[sixthParam-1]) + if err != nil { + return + } + + fallthrough + case fifthParam: + err = o.setCount(params[fifthParam-1]) + if err != nil { + return + } + + fallthrough + case fourthParam: + err = o.setTimeout(params[fourthParam-1]) + if err != nil { + return + } + + fallthrough + case thirdParam: + err = o.setDNSType(params[thirdParam-1]) + if err != nil { + return + } + + fallthrough + case secondParam: + o.name = params[secondParam-1] + + fallthrough + case firstParam: + err = o.setIP(params[firstParam-1]) + if err != nil { + return o, zbxerr.New(fmt.Sprintf("invalid fist parameter, %s", err.Error())) + } + + fallthrough + case noneParam: + err = o.setDefaults() + if err != nil { + return + } + default: + err = zbxerr.ErrorTooManyParameters + + return + } + + return +} + +func (o *options) setIP(ip string) error { + if ip == "" { + return nil + } + + if !isValidIP(ip) { + return fmt.Errorf("invalid IP address, %s", ip) + } + + o.ip = net.JoinHostPort(ip, "53") + + return nil +} + +func isValidIP(ip string) bool { + if r := net.ParseIP(ip); r == nil { + return false + } + + return true +} + +func (o *options) setProtocol(protocol string) error { + switch protocol { + case tcpProtocol: + o.protocol = tcpProtocol + case udpProtocol, "": + o.protocol = udpProtocol + default: + return zbxerr.New("invalid sixth parameter") + } + + return nil +} + +func (o *options) setCount(c string) error { + if c == "" { + return nil + } + + count, err := strconv.Atoi(c) + if err != nil { + return zbxerr.New(fmt.Sprintf("invalid fifth parameter, %s", err.Error())) + } + + if count <= 0 { + return zbxerr.New("invalid fifth parameter") + } + + o.count = count + + return nil +} + +func (o *options) setTimeout(timeout string) error { + if timeout == "" { + return nil + } + + t, err := strconv.Atoi(timeout) + if err != nil { + return zbxerr.New(fmt.Sprintf("invalid fourth parameter, %s", err.Error())) + } + + if t <= 0 { + return zbxerr.New("invalid fourth parameter") + } + + o.timeout = time.Duration(t) * time.Second + + return nil +} + +func (o *options) setDNSType(dnsType string) error { + if dnsType == "" { + return nil + } + + t, ok := dnsTypes[strings.ToUpper(dnsType)] + if !ok { + return zbxerr.New(fmt.Sprintf("invalid third parameter, unknown dns type %s", dnsType)) + } + + o.dnsType = t + + return nil +} + +func (o *options) setDefaults() error { + if o.ip == "" { + err := o.setDefaultIP() + if err != nil { + return zbxerr.New(err.Error()) + } + } + + if o.name == "" { + o.setDefaultName() + } + + if o.dnsType == dns.TypeNone { + o.dnsType = dns.TypeSOA + } + + if o.timeout < 1 { + o.timeout = 1 * time.Second + } + + if o.count < 1 { + o.count = 2 + } + + if o.protocol == "" { + o.protocol = udpProtocol + } + + return nil +} + +func (o *options) setDefaultName() { + o.name = "zabbix.com" +} + +func runQuery(resolver, domain, net string, record uint16, timeout time.Duration) (*dns.Msg, error) { + c := new(dns.Client) + c.Net = net + c.DialTimeout = timeout + c.ReadTimeout = timeout + c.WriteTimeout = timeout + + m := &dns.Msg{ + MsgHdr: dns.MsgHdr{ + CheckingDisabled: false, + RecursionDesired: true, + Opcode: dns.OpcodeQuery, + Rcode: dns.RcodeSuccess, + }, + Question: make([]dns.Question, 1), + } + + m.Question[0] = dns.Question{Name: dns.Fqdn(domain), Qtype: record, Qclass: dns.ClassINET} + r, _, err := c.Exchange(m, resolver) + + return r, err +} + +func init() { + plugin.RegisterMetrics(&impl, "DNS", + "net.dns", "Checks if DNS service is up.", + "net.dns.record", "Performs a DNS query.", + ) +} diff --git a/src/go/plugins/zabbix/sync/sync_nix.go b/src/go/plugins/net/dns/dns_nix.go index 9b6ec074977..8c617e17d34 100644 --- a/src/go/plugins/zabbix/sync/sync_nix.go +++ b/src/go/plugins/net/dns/dns_nix.go @@ -1,9 +1,8 @@ -//go:build !windows // +build !windows /* ** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA +** Copyright (C) 2001-2021 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by @@ -20,11 +19,26 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -package zabbixsync +package dns -func getMetrics() []string { - return []string{ - "net.dns", "Checks if DNS service is up.", - "net.dns.record", "Performs DNS query.", +import ( + "fmt" + "os" + "strings" +) + +func (o *options) setDefaultIP() (err error) { + data, err := os.ReadFile("/etc/resolv.conf") + if err != nil { + return + } + + s := strings.Split(string(data), "\n") + for _, tmp := range s { + if strings.HasPrefix(tmp, "nameserver") { + return o.setIP(strings.TrimSpace(strings.TrimPrefix(tmp, "nameserver"))) + } } + + return fmt.Errorf("cannot find default dns nameserver") } diff --git a/src/go/plugins/net/dns/dns_windows.go b/src/go/plugins/net/dns/dns_windows.go new file mode 100644 index 00000000000..baf45c3d40d --- /dev/null +++ b/src/go/plugins/net/dns/dns_windows.go @@ -0,0 +1,79 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +package dns + +import ( + "strings" + "unsafe" + + "golang.org/x/sys/windows" + "zabbix.com/pkg/zbxerr" +) + +func (o *options) setDefaultIP() error { + l := uint32(20000) + b := make([]byte, l) + + if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l); err != nil { + return err + } + + var addresses []*windows.IpAdapterAddresses + for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); addr != nil; addr = addr.Next { + addresses = append(addresses, addr) + } + + resolvers := map[string]bool{} + for _, addr := range addresses { + for next := addr.FirstUnicastAddress; next != nil; next = next.Next { + if addr.OperStatus != windows.IfOperStatusUp { + continue + } + + if next.Address.IP() != nil { + for dnsServer := addr.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next { + ip := dnsServer.Address.IP() + if ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { + continue + } + + if ip.To16() != nil && strings.HasPrefix(ip.To16().String(), "fec0:") { + continue + } + + resolvers[ip.String()] = true + } + + break + } + } + } + + servers := []string{} + for server := range resolvers { + servers = append(servers, server) + } + + if len(servers) < 0 { + return zbxerr.New("no dns server found") + } + + return o.setIP(servers[0]) +} diff --git a/src/go/plugins/plugins_darwin.go b/src/go/plugins/plugins_darwin.go index 273324cdf64..fb8a166049b 100644 --- a/src/go/plugins/plugins_darwin.go +++ b/src/go/plugins/plugins_darwin.go @@ -39,5 +39,4 @@ import ( _ "zabbix.com/plugins/web/page" _ "zabbix.com/plugins/zabbix/async" _ "zabbix.com/plugins/zabbix/stats" - _ "zabbix.com/plugins/zabbix/sync" ) diff --git a/src/go/plugins/plugins_linux.go b/src/go/plugins/plugins_linux.go index 33788d49989..d6d8bc9c87f 100644 --- a/src/go/plugins/plugins_linux.go +++ b/src/go/plugins/plugins_linux.go @@ -29,6 +29,7 @@ import ( _ "zabbix.com/plugins/mongodb" _ "zabbix.com/plugins/mqtt" _ "zabbix.com/plugins/mysql" + _ "zabbix.com/plugins/net/dns" _ "zabbix.com/plugins/net/netif" _ "zabbix.com/plugins/net/tcp" _ "zabbix.com/plugins/net/udp" @@ -55,5 +56,4 @@ import ( _ "zabbix.com/plugins/web/page" _ "zabbix.com/plugins/zabbix/async" _ "zabbix.com/plugins/zabbix/stats" - _ "zabbix.com/plugins/zabbix/sync" ) diff --git a/src/go/plugins/plugins_windows.go b/src/go/plugins/plugins_windows.go index 0c5c15c0dc8..a7d232bcab6 100644 --- a/src/go/plugins/plugins_windows.go +++ b/src/go/plugins/plugins_windows.go @@ -27,6 +27,7 @@ import ( _ "zabbix.com/plugins/mongodb" _ "zabbix.com/plugins/mqtt" _ "zabbix.com/plugins/mysql" + _ "zabbix.com/plugins/net/dns" _ "zabbix.com/plugins/net/netif" _ "zabbix.com/plugins/net/tcp" _ "zabbix.com/plugins/net/udp" @@ -55,5 +56,4 @@ import ( _ "zabbix.com/plugins/windows/wmi" _ "zabbix.com/plugins/zabbix/async" _ "zabbix.com/plugins/zabbix/stats" - _ "zabbix.com/plugins/zabbix/sync" ) diff --git a/src/go/plugins/smart/smart.go b/src/go/plugins/smart/smart.go index 48b15152511..afa7f5a5ec6 100644 --- a/src/go/plugins/smart/smart.go +++ b/src/go/plugins/smart/smart.go @@ -21,7 +21,6 @@ package smart import ( "encoding/json" - "strings" "zabbix.com/pkg/conf" "zabbix.com/pkg/plugin" @@ -83,7 +82,7 @@ func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) for _, dev := range r.devices { out = append(out, device{ Name: cutPrefix(dev.Info.Name), - DeviceType: strings.ToUpper(getType(dev.Info.DevType, dev.RotationRate)), + DeviceType: getType(dev.Info.DevType, dev.RotationRate, dev.SmartAttributes.Table), Model: dev.ModelName, SerialNumber: dev.SerialNumber, }) } @@ -127,13 +126,7 @@ func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) } for _, dev := range r.devices { - var t string - if dev.RotationRate == 0 { - t = "SSD" - } else { - t = "HDD" - } - + t := getAttributeType(dev.Info.DevType, dev.RotationRate, dev.SmartAttributes.Table) for _, attr := range dev.SmartAttributes.Table { out = append( out, attribute{ @@ -169,52 +162,108 @@ func setDiskFields(deviceJsons map[string]jsonDevice) (out []interface{}, err er } b["disk_name"] = cutPrefix(k) + b["disk_type"] = getType(getTypeFromJson(b), getRateFromJson(b), getTablesFromJson(b)) - var devType string + out = append(out, b) + } - if dev, ok := b["device"]; ok { - s, ok := dev.(string) - if ok { - info := make(map[string]string) - if err = json.Unmarshal([]byte(s), &info); err != nil { - return out, zbxerr.ErrorCannotUnmarshalJSON.Wrap(err) - } + return +} - devType = info["type"] - } +func getRateFromJson(in map[string]interface{}) (out int) { + if r, ok := in[rotationRateFieldName]; ok { + switch rate := r.(type) { + case int: + out = rate + case float64: + out = int(rate) } + } - rateInt := -1 + return +} - if rate, ok := b["rotation_rate"]; ok { - switch r := rate.(type) { - case int: - rateInt = r - case float64: - rateInt = int(r) +func getTypeFromJson(in map[string]interface{}) (out string) { + if dev, ok := in[deviceFieldName]; ok { + m, ok := dev.(map[string]interface{}) + if ok { + if t, ok := m[typeFieldName]; ok { + s, ok := t.(string) + if ok { + out = s + } } } + } - b["disk_type"] = getType(devType, rateInt) - out = append(out, b) + return +} + +func getTablesFromJson(in map[string]interface{}) (out []table) { + attr, ok := in[ataSmartAttrFieldName] + if !ok { + return + } + + a, ok := attr.(map[string]interface{}) + if !ok { + return + } + + tables, ok := a[ataSmartAttrTableFieldName] + if !ok { + return + } + + tmp, ok := tables.([]interface{}) + if !ok { + return + } + + b, err := json.Marshal(tmp) + if err != nil { + return + } + + err = json.Unmarshal(b, &out) + if err != nil { + return } return } -func getType(devType string, rate int) (out string) { - out = "unknown" - if devType == "nvme" { - out = "nvme" - } else { - if rate == 0 { - out = "ssd" - } else if rate > 0 { - out = "hdd" +func getAttributeType(devType string, rate int, tables []table) string { + if devType == unknownType { + return unknownType + } + + return getTypeByRateAndAttr(rate, tables) +} + +func getType(devType string, rate int, tables []table) string { + switch devType { + case nvmeType: + return nvmeType + case unknownType: + return unknownType + default: + return getTypeByRateAndAttr(rate, tables) + } +} + +func getTypeByRateAndAttr(rate int, tables []table) string { + if rate > 0 { + return hddType + } + + for _, t := range tables { + if t.Attrname == spinUpAttrName { + return hddType } } - return + return ssdType } func init() { diff --git a/src/go/plugins/smart/smart_test.go b/src/go/plugins/smart/smart_test.go index 1ca089c02d5..eb73c16c8c6 100644 --- a/src/go/plugins/smart/smart_test.go +++ b/src/go/plugins/smart/smart_test.go @@ -21,9 +21,18 @@ package smart import ( "fmt" + "reflect" "testing" ) +var ( + table1 = table{"test1", 1, 11} + table2 = table{"test2", 2, 22} + table3 = table{"test3", 3, 33} + table4 = table{"test4", 4, 44} + attrTable = table{"Spin_Up_Time", 5, 55} +) + func Test_setDiskFields(t *testing.T) { //nolint:lll jsonSdaStr := `{"device": {"name": "/dev/sda","info_name": "/dev/sda [SAT]","type": "sat","protocol": "ATA"},"rotation_rate": 0}` @@ -63,27 +72,192 @@ func Test_setDiskFields(t *testing.T) { } } +func Test_getRateFromJson(t *testing.T) { + type args struct { + in map[string]interface{} + } + tests := []struct { + name string + args args + wantOut int + }{ + {"rate", args{map[string]interface{}{"rotation_rate": 10}}, 10}, + {"multiple_fields", args{map[string]interface{}{"foobar": "abc", "rotation_rate": 10}}, 10}, + {"no_rate", args{map[string]interface{}{"foobar": "abc"}}, 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotOut := getRateFromJson(tt.args.in); gotOut != tt.wantOut { + t.Errorf("getRateFromJson() = %v, want %v", gotOut, tt.wantOut) + } + }) + } +} + +func Test_getTypeFromJson(t *testing.T) { + map1 := make(map[string]interface{}) + map1["device"] = map[string]interface{}{"type": "sat"} + + map2 := make(map[string]interface{}) + map2["device"] = map[string]interface{}{"type": "sat", "foobar": "abc"} + + map3 := make(map[string]interface{}) + map3["device"] = map[string]interface{}{"foobar": "abc"} + + type args struct { + in map[string]interface{} + } + tests := []struct { + name string + args args + wantOut string + }{ + {"type", args{map1}, "sat"}, + {"multiple_fields", args{map2}, "sat"}, + {"no_type", args{map3}, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotOut := getTypeFromJson(tt.args.in); gotOut != tt.wantOut { + t.Errorf("getTypeFromJson() = %v, want %v", gotOut, tt.wantOut) + } + }) + } +} + +func Test_getTablesFromJson(t *testing.T) { + map1 := make(map[string]interface{}) + map1["table"] = []interface{}{table1, table2, attrTable} + + map2 := make(map[string]interface{}) + map2["table"] = []interface{}{table1, table2, table4} + + attrTable1 := map[string]interface{}{"ata_smart_attributes": map1} + attrTable2 := map[string]interface{}{"ata_smart_attributes": map2} + attrTable3 := map[string]interface{}{"ata_smart_attributes": nil} + attrTable4 := map[string]interface{}{"ata_smart_attributes": []table{}} + attrTable5 := map[string]interface{}{"ata_smart_attributes": map[string][]table{}} + + type args struct { + in map[string]interface{} + } + tests := []struct { + name string + args args + want []table + }{ + {"attr_table", args{attrTable1}, []table{table1, table2, attrTable}}, + {"no_attr_table", args{attrTable2}, []table{table1, table2, table4}}, + {"no_table", args{attrTable3}, nil}, + {"incorrect_table_value", args{attrTable4}, nil}, + {"empty_map", args{attrTable5}, nil}, + {"no_ata_attributes", args{nil}, nil}, + {"empty_ata_attributes", args{map[string]interface{}{}}, nil}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getTablesFromJson(tt.args.in); !reflect.DeepEqual(got, tt.want) { + t.Errorf("getTablesFromJson() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_getAttributeType(t *testing.T) { + type args struct { + devType string + rate int + tables []table + } + tests := []struct { + name string + args args + want string + }{ + {"ssd_no_tables", args{"SAT", 0, nil}, "ssd"}, + {"ssd_tables_no_spin_up_table", args{"SAT", 0, []table{table1, table2, table4}}, "ssd"}, + {"hdd_no_tables", args{"SAT", 12, nil}, "hdd"}, + {"hdd_rate_spin_up_table", args{"SAT", 12, []table{table1, table2, table4, attrTable}}, "hdd"}, + {"hdd_no_rate_spin_up_table", args{"SAT", 0, []table{table1, table2, table4, attrTable}}, "hdd"}, + {"hdd_no_spin_up_table", args{"SAT", 12, []table{table1, table2, table4}}, "hdd"}, + {"unknown_no_attr_table", args{"unknown", 1000, []table{table1, table2, table4}}, "unknown"}, + {"unknown_value_table", args{"unknown", 1000, []table{table1, table2, table4, attrTable}}, "unknown"}, + {"unknown_no_rate_no_tables", args{"unknown", 0, nil}, "unknown"}, + {"unknown_no_rate_no_attr_table", args{"unknown", 0, []table{table1, table2, table4}}, "unknown"}, + {"unknown_no_rate_value_table", args{"unknown", 0, []table{table1, table2, table4, attrTable}}, "unknown"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getAttributeType(tt.args.devType, tt.args.rate, tt.args.tables); got != tt.want { + t.Errorf("getAttributeType() = %v, want %v", got, tt.want) + } + }) + } +} + func Test_getType(t *testing.T) { type args struct { devType string rate int + tables []table } tests := []struct { name string args args wantOut string }{ - {"ssd", args{"SAT", 0}, "ssd"}, - {"hdd", args{"SAT", 12}, "hdd"}, - {"nvme", args{"nvme", 0}, "nvme"}, - {"unknown", args{"SAT", -1}, "unknown"}, + {"ssd_no_tables", args{"SAT", 0, nil}, "ssd"}, + {"ssd_tables_no_spin_up_table", args{"SAT", 0, []table{table1, table2, table4}}, "ssd"}, + {"hdd_no_tables", args{"SAT", 12, nil}, "hdd"}, + {"hdd_rate_spin_up_table", args{"SAT", 12, []table{table1, table2, table4, attrTable}}, "hdd"}, + {"hdd_no_rate_spin_up_table", args{"SAT", 0, []table{table1, table2, table4, attrTable}}, "hdd"}, + {"hdd_no_spin_up_table", args{"SAT", 12, []table{table1, table2, table4}}, "hdd"}, + {"nvme_no_tables", args{"nvme", 1000, nil}, "nvme"}, + {"nvme_no_attr_table", args{"nvme", 1000, []table{table1, table2, table4}}, "nvme"}, + {"nvme_value_table", args{"nvme", 1000, []table{table1, table2, table4, attrTable}}, "nvme"}, + {"nvme_no_rate_no_tables", args{"nvme", 0, nil}, "nvme"}, + {"nvme_no_rate_no_attr_table", args{"nvme", 0, []table{table1, table2, table4}}, "nvme"}, + {"nvme_no_rate_value_table", args{"nvme", 0, []table{table1, table2, table4, attrTable}}, "nvme"}, + {"unknown_no_tables", args{"unknown", 1000, nil}, "unknown"}, + {"unknown_no_attr_table", args{"unknown", 1000, []table{table1, table2, table4}}, "unknown"}, + {"unknown_value_table", args{"unknown", 1000, []table{table1, table2, table4, attrTable}}, "unknown"}, + {"unknown_no_rate_no_tables", args{"unknown", 0, nil}, "unknown"}, + {"unknown_no_rate_no_attr_table", args{"unknown", 0, []table{table1, table2, table4}}, "unknown"}, + {"unknown_no_rate_value_table", args{"unknown", 0, []table{table1, table2, table4, attrTable}}, "unknown"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if gotOut := getType(tt.args.devType, tt.args.rate); gotOut != tt.wantOut { + if gotOut := getType(tt.args.devType, tt.args.rate, tt.args.tables); gotOut != tt.wantOut { t.Errorf("getType() = %v, want %v", gotOut, tt.wantOut) } }) } } + +func Test_getTypeByRateAndAttr(t *testing.T) { + type args struct { + rate int + tables []table + } + tests := []struct { + name string + args args + want string + }{ + {"zero_rate_zero_spin_up", args{0, []table{table1, table2}}, "ssd"}, + {"zero_rate_no_tables", args{0, nil}, "ssd"}, + {"negative_rate_no_tables", args{-1000, nil}, "ssd"}, + {"positive_rate_spin_up_table", args{12, []table{table1, table2, table3, attrTable}}, "hdd"}, + {"positive_rate_no_tables", args{12, nil}, "hdd"}, + {"zero_rate_spin_up_table", args{0, []table{table1, table2, table3, attrTable}}, "hdd"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getTypeByRateAndAttr(tt.args.rate, tt.args.tables); got != tt.want { + t.Errorf("getTypeByRate() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/src/go/plugins/smart/smartfs.go b/src/go/plugins/smart/smartfs.go index 469579a3099..2942525c08f 100644 --- a/src/go/plugins/smart/smartfs.go +++ b/src/go/plugins/smart/smartfs.go @@ -33,9 +33,25 @@ import ( "zabbix.com/pkg/zbxerr" ) -const supportedSmartctl = 7.1 +const ( + supportedSmartctl = 7.1 -const satType = "sat" + satType = "sat" + nvmeType = "nvme" + unknownType = "unknown" + ssdType = "ssd" + hddType = "hdd" + + spinUpAttrName = "Spin_Up_Time" + + ataSmartAttrFieldName = "ata_smart_attributes" + ataSmartAttrTableFieldName = "table" + + rotationRateFieldName = "rotation_rate" + + deviceFieldName = "device" + typeFieldName = "type" +) var ( cpuCount int @@ -374,7 +390,7 @@ runner: device, err := r.plugin.executeSmartctl(fmt.Sprintf("-a %s -j ", name), false) if err != nil { r.plugin.Tracef( - "stopped looking for RAID devices of %s type, err:", + "stopped looking for RAID devices of %s type, err: %s", raid.rType, fmt.Errorf("failed to get RAID disk data from smartctl: %s", err.Error()), ) @@ -384,8 +400,8 @@ runner: var dp deviceParser if err = json.Unmarshal(device, &dp); err != nil { r.plugin.Tracef( - "stopped looking for RAID devices of %s type, err:", - raid.rType, fmt.Errorf("failed to get RAID disk data from smartctl: %s", err.Error()), + "stopped looking for RAID devices of %s type, err: %s", + raid.rType, fmt.Errorf("failed to parse RAID disk data from smartctl: %s", err.Error()), ) continue runner @@ -394,7 +410,7 @@ runner: err = dp.checkErr() if err != nil { r.plugin.Tracef( - "stopped looking for RAID devices of %s type, err:", + "stopped looking for RAID devices of %s type, err: %s", raid.rType, fmt.Errorf("failed to get disk data from smartctl: %s", err.Error()), ) diff --git a/src/go/plugins/system/cpu/cpu.go b/src/go/plugins/system/cpu/cpu.go index e2eb6e9e86c..5f22df69edf 100644 --- a/src/go/plugins/system/cpu/cpu.go +++ b/src/go/plugins/system/cpu/cpu.go @@ -23,6 +23,8 @@ import ( "encoding/json" "errors" "strconv" + + "zabbix.com/pkg/zbxerr" ) const pluginName = "Cpu" @@ -101,29 +103,21 @@ func (p *Plugin) getCpuDiscovery(params []string) (result interface{}, err error } func (p *Plugin) getCpuNum(params []string) (result interface{}, err error) { - mask := cpuStatusOnline switch len(params) { case 1: switch params[0] { case "", "online": - // default value, already initialized + return numCPUOnline(), nil case "max": - mask = cpuStatusOnline | cpuStatusOffline + return numCPUConf(), nil default: return nil, errors.New("Invalid first parameter.") } case 0: + return numCPUOnline(), nil default: - return nil, errors.New("Too many parameters.") - } - - var num int - for i := 1; i < len(p.cpus); i++ { - if p.cpus[i].status&mask != 0 { - num++ - } + return nil, zbxerr.ErrorTooManyParameters } - return num, nil } func periodByMode(mode string) (period historyIndex) { diff --git a/src/go/plugins/system/cpu/cpu_linux.go b/src/go/plugins/system/cpu/cpu_linux.go index e9eb21e8695..d52fff06fd4 100644 --- a/src/go/plugins/system/cpu/cpu_linux.go +++ b/src/go/plugins/system/cpu/cpu_linux.go @@ -77,11 +77,14 @@ func (p *Plugin) Collect() (err error) { if i, err = strconv.ParseInt(fields[0][3:], 10, 32); err != nil { return } - if index = int(i); index < 0 || index+1 >= len(p.cpus) { + + if index = int(i); index < 0 { p.Debugf("invalid CPU index %d", index) continue } + p.addCpu(index) + status = cpuStatusOnline } else { index = -1 @@ -112,12 +115,32 @@ func (p *Plugin) Collect() (err error) { return nil } -func numCPU() int { +func (p *Plugin) addCpu(index int) { + if p == nil || p.cpus == nil { + return + } + + if index == 0 { + return + } + + if index+1 >= len(p.cpus) { + for idx := p.cpus[len(p.cpus)-1].index; idx < index; idx++ { + p.cpus = append(p.cpus, &cpuUnit{index: idx + 1, status: cpuStatusOffline}) + } + } +} + +func numCPUConf() int { return int(C.sysconf(C._SC_NPROCESSORS_CONF)) } +func numCPUOnline() int { + return int(C.sysconf(C._SC_NPROCESSORS_ONLN)) +} + func (p *Plugin) Start() { - p.cpus = p.newCpus(numCPU()) + p.cpus = p.newCpus(numCPUConf()) } func (p *Plugin) Stop() { diff --git a/src/go/plugins/system/cpu/cpu_linux_test.go b/src/go/plugins/system/cpu/cpu_linux_test.go new file mode 100644 index 00000000000..87d719352ca --- /dev/null +++ b/src/go/plugins/system/cpu/cpu_linux_test.go @@ -0,0 +1,136 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +package cpu + +import ( + "reflect" + "testing" +) + +func TestPlugin_addCpu(t *testing.T) { + type fields struct { + cpus []*cpuUnit + } + type args struct { + index int + } + tests := []struct { + name string + fields fields + args args + want []*cpuUnit + }{ + { + "one_offline_cpu", + fields{ + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + }, + }, + args{2}, + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + {index: 2, status: cpuStatusOffline}, + }, + }, + { + "two_offline_cpu", + fields{ + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + }, + }, + args{3}, + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + {index: 2, status: cpuStatusOffline}, + {index: 3, status: cpuStatusOffline}, + }, + }, + { + "ten_offline_cpu", + fields{ + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + }, + }, + args{11}, + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + {index: 2, status: cpuStatusOffline}, + {index: 3, status: cpuStatusOffline}, + {index: 4, status: cpuStatusOffline}, + {index: 5, status: cpuStatusOffline}, + {index: 6, status: cpuStatusOffline}, + {index: 7, status: cpuStatusOffline}, + {index: 8, status: cpuStatusOffline}, + {index: 9, status: cpuStatusOffline}, + {index: 10, status: cpuStatusOffline}, + {index: 11, status: cpuStatusOffline}, + }, + }, + { + "no_offline_cpu", + fields{ + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + }, + }, + args{1}, + []*cpuUnit{ + {index: -1, status: cpuStatusOffline}, + {index: 0, status: cpuStatusOffline}, + {index: 1, status: cpuStatusOffline}, + }, + }, + { + "empty", fields{[]*cpuUnit{}}, args{}, []*cpuUnit{}, + }, + { + "nil", fields{nil}, args{}, nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Plugin{ + cpus: tt.fields.cpus, + } + p.addCpu(tt.args.index) + + if !reflect.DeepEqual(p.cpus, tt.want) { + t.Errorf("addCpu() got = %v, want %v", p.cpus, tt.want) + } + }) + } +} diff --git a/src/go/plugins/system/cpu/cpu_windows.go b/src/go/plugins/system/cpu/cpu_windows.go index 0b175a17dfe..eff02894286 100644 --- a/src/go/plugins/system/cpu/cpu_windows.go +++ b/src/go/plugins/system/cpu/cpu_windows.go @@ -43,6 +43,15 @@ const ( defaultIndex = 60 ) +func numCPUOnline() int { + return numCPU() +} + +func numCPUConf() int { + // unsupported on Windows + return 0 +} + func numCPU() (numCpu int) { size, err := win32.GetLogicalProcessorInformationEx(win32.RelationProcessorCore, nil) if err != nil { diff --git a/src/go/plugins/zabbix/sync/sync.go b/src/go/plugins/zabbix/sync/sync.go deleted file mode 100644 index dde57d8d57b..00000000000 --- a/src/go/plugins/zabbix/sync/sync.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - -package zabbixsync - -import ( - "zabbix.com/pkg/plugin" - "zabbix.com/pkg/zbxlib" -) - -// Plugin - -type Plugin struct { - plugin.Base -} - -var impl Plugin - -func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) { - return zbxlib.ExecuteCheck(key, params) -} - -func init() { - plugin.RegisterMetrics(&impl, "ZabbixSync", getMetrics()...) - impl.SetCapacity(1) -} diff --git a/src/go/plugins/zabbix/sync/sync_windows.go b/src/go/plugins/zabbix/sync/sync_windows.go deleted file mode 100644 index 428885b1a66..00000000000 --- a/src/go/plugins/zabbix/sync/sync_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - -package zabbixsync - -func getMetrics() []string { - return []string{ - "net.dns", "Checks if DNS service is up.", - "net.dns.record", "Performs DNS query.", - } -} diff --git a/src/libs/zbxcrypto/tls.c b/src/libs/zbxcrypto/tls.c index 1230f35a04f..bf63612a84f 100644 --- a/src/libs/zbxcrypto/tls.c +++ b/src/libs/zbxcrypto/tls.c @@ -3498,6 +3498,66 @@ out1: return ret; } #elif defined(HAVE_OPENSSL) +static int zbx_tls_get_error(const SSL *s, int res, const char *func, size_t *error_alloc, size_t *error_offset, + char **error) +{ + int result_code; + + result_code = SSL_get_error(s, res); + + switch (result_code) + { + case SSL_ERROR_NONE: /* handshake successful */ + return SUCCEED; + case SSL_ERROR_ZERO_RETURN: + zbx_snprintf_alloc(error, error_alloc, error_offset, + "%s() TLS connection has been closed during read", func); + return FAIL; + case SSL_ERROR_SYSCALL: + if (0 == ERR_peek_error()) + { + if (0 == res) + { + zbx_snprintf_alloc(error, error_alloc, error_offset, + "%s() connection closed by peer", func); + } + else if (-1 == res) + { + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s()" + " I/O error: %s", func, + strerror_from_system(zbx_socket_last_error())); + } + else + { + /* "man SSL_get_error" describes only res == 0 and res == -1 for */ + /* SSL_ERROR_SYSCALL case */ + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s()" + " returned undocumented code %d", func, res); + } + } + else + { + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s() set" + " result code to SSL_ERROR_SYSCALL:", func); + zbx_tls_error_msg(error, error_alloc, error_offset); + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s", info_buf); + } + return FAIL; + case SSL_ERROR_SSL: + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s() set" + " result code to SSL_ERROR_SSL:", func); + zbx_tls_error_msg(error, error_alloc, error_offset); + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s", info_buf); + return FAIL; + default: + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s() set result code" + " to %d", func, result_code); + zbx_tls_error_msg(error, error_alloc, error_offset); + zbx_snprintf_alloc(error, error_alloc, error_offset, "%s", info_buf); + return FAIL; + } +} + int zbx_tls_connect(zbx_socket_t *s, unsigned int tls_connect, const char *tls_arg1, const char *tls_arg2, char **error) { @@ -3614,8 +3674,6 @@ int zbx_tls_connect(zbx_socket_t *s, unsigned int tls_connect, const char *tls_a #endif if (1 != (res = SSL_connect(s->tls_ctx->ctx))) { - int result_code; - #if defined(_WINDOWS) if (s->timeout < zbx_time() - sec) zbx_alarm_flag_set(); @@ -3639,59 +3697,8 @@ int zbx_tls_connect(zbx_socket_t *s, unsigned int tls_connect, const char *tls_a } } - result_code = SSL_get_error(s->tls_ctx->ctx, res); - - switch (result_code) - { - case SSL_ERROR_NONE: /* handshake successful */ - break; - case SSL_ERROR_ZERO_RETURN: - zbx_snprintf_alloc(error, &error_alloc, &error_offset, - "TLS connection has been closed during handshake"); - goto out; - case SSL_ERROR_SYSCALL: - if (0 == ERR_peek_error()) - { - if (0 == res) - { - zbx_snprintf_alloc(error, &error_alloc, &error_offset, - "connection closed by peer"); - } - else if (-1 == res) - { - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "SSL_connect()" - " I/O error: %s", - strerror_from_system(zbx_socket_last_error())); - } - else - { - /* "man SSL_get_error" describes only res == 0 and res == -1 for */ - /* SSL_ERROR_SYSCALL case */ - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "SSL_connect()" - " returned undocumented code %d", res); - } - } - else - { - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "SSL_connect() set" - " result code to SSL_ERROR_SYSCALL:"); - zbx_tls_error_msg(error, &error_alloc, &error_offset); - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "%s", info_buf); - } - goto out; - case SSL_ERROR_SSL: - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "SSL_connect() set" - " result code to SSL_ERROR_SSL:"); - zbx_tls_error_msg(error, &error_alloc, &error_offset); - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "%s", info_buf); - goto out; - default: - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "SSL_connect() set result code" - " to %d", result_code); - zbx_tls_error_msg(error, &error_alloc, &error_offset); - zbx_snprintf_alloc(error, &error_alloc, &error_offset, "%s", info_buf); - goto out; - } + if (FAIL == zbx_tls_get_error(s->tls_ctx->ctx, res, "SSL_connect", &error_alloc, &error_offset, error)) + goto out; } if (ZBX_TCP_SEC_TLS_CERT == tls_connect) @@ -4289,34 +4296,25 @@ out1: ssize_t zbx_tls_write(zbx_socket_t *s, const char *buf, size_t len, char **error) { -#if defined(_WINDOWS) - double sec; -#endif #if defined(HAVE_GNUTLS) ssize_t res; #elif defined(HAVE_OPENSSL) int res; #endif -#if defined(_WINDOWS) - zbx_alarm_flag_clear(); - sec = zbx_time(); -#endif #if defined(HAVE_OPENSSL) info_buf[0] = '\0'; /* empty buffer for zbx_openssl_info_cb() messages */ #endif do { res = ZBX_TLS_WRITE(s->tls_ctx->ctx, buf, len); -#if defined(_WINDOWS) - if (s->timeout < zbx_time() - sec) - zbx_alarm_flag_set(); -#endif +#if !defined(_WINDOWS) if (SUCCEED == zbx_alarm_timed_out()) { *error = zbx_strdup(*error, ZBX_TLS_WRITE_FUNC_NAME "() timed out"); return ZBX_PROTO_ERROR; } +#endif } while (SUCCEED == ZBX_TLS_WANT_WRITE(res)); @@ -4331,24 +4329,12 @@ ssize_t zbx_tls_write(zbx_socket_t *s, const char *buf, size_t len, char **error #elif defined(HAVE_OPENSSL) if (0 >= res) { - int result_code; + size_t error_alloc = 0, error_offset = 0; - result_code = SSL_get_error(s->tls_ctx->ctx, res); - - if (0 == res && SSL_ERROR_ZERO_RETURN == result_code) - { - *error = zbx_strdup(*error, "connection closed during write"); - } - else + if (SUCCEED == zbx_tls_get_error(s->tls_ctx->ctx, res, ZBX_TLS_WRITE_FUNC_NAME, &error_alloc, + &error_offset, error)) { - char *err = NULL; - size_t error_alloc = 0, error_offset = 0; - - zbx_snprintf_alloc(&err, &error_alloc, &error_offset, "TLS write set result code to" - " %d:", result_code); - zbx_tls_error_msg(&err, &error_alloc, &error_offset); - *error = zbx_dsprintf(*error, "%s%s", err, info_buf); - zbx_free(err); + *error = zbx_strdup(*error, ZBX_TLS_WRITE_FUNC_NAME "() unexpected result code"); } return ZBX_PROTO_ERROR; @@ -4360,34 +4346,25 @@ ssize_t zbx_tls_write(zbx_socket_t *s, const char *buf, size_t len, char **error ssize_t zbx_tls_read(zbx_socket_t *s, char *buf, size_t len, char **error) { -#if defined(_WINDOWS) - double sec; -#endif #if defined(HAVE_GNUTLS) ssize_t res; #elif defined(HAVE_OPENSSL) int res; #endif -#if defined(_WINDOWS) - zbx_alarm_flag_clear(); - sec = zbx_time(); -#endif #if defined(HAVE_OPENSSL) info_buf[0] = '\0'; /* empty buffer for zbx_openssl_info_cb() messages */ #endif do { res = ZBX_TLS_READ(s->tls_ctx->ctx, buf, len); -#if defined(_WINDOWS) - if (s->timeout < zbx_time() - sec) - zbx_alarm_flag_set(); -#endif +#if !defined(_WINDOWS) if (SUCCEED == zbx_alarm_timed_out()) { *error = zbx_strdup(*error, ZBX_TLS_READ_FUNC_NAME "() timed out"); return ZBX_PROTO_ERROR; } +#endif } while (SUCCEED == ZBX_TLS_WANT_READ(res)); @@ -4403,24 +4380,12 @@ ssize_t zbx_tls_read(zbx_socket_t *s, char *buf, size_t len, char **error) #elif defined(HAVE_OPENSSL) if (0 >= res) { - int result_code; - - result_code = SSL_get_error(s->tls_ctx->ctx, res); + size_t error_alloc = 0, error_offset = 0; - if (0 == res && SSL_ERROR_ZERO_RETURN == result_code) + if (SUCCEED == zbx_tls_get_error(s->tls_ctx->ctx, res, ZBX_TLS_READ_FUNC_NAME, &error_alloc, + &error_offset, error)) { - *error = zbx_strdup(*error, "connection closed during read"); - } - else - { - char *err = NULL; - size_t error_alloc = 0, error_offset = 0; - - zbx_snprintf_alloc(&err, &error_alloc, &error_offset, "TLS read set result code to" - " %d:", result_code); - zbx_tls_error_msg(&err, &error_alloc, &error_offset); - *error = zbx_dsprintf(*error, "%s%s", err, info_buf); - zbx_free(err); + *error = zbx_strdup(*error, ZBX_TLS_READ_FUNC_NAME "() unexpected result code"); } return ZBX_PROTO_ERROR; diff --git a/src/libs/zbxdbhigh/proxy.c b/src/libs/zbxdbhigh/proxy.c index c84fa56f61b..8941b175cd3 100644 --- a/src/libs/zbxdbhigh/proxy.c +++ b/src/libs/zbxdbhigh/proxy.c @@ -3547,7 +3547,7 @@ static int process_history_data_by_itemids(zbx_socket_t *sock, zbx_client_item_v double sec; DC_ITEM *items; char *error = NULL; - zbx_uint64_t itemids[ZBX_HISTORY_VALUES_MAX]; + zbx_uint64_t itemids[ZBX_HISTORY_VALUES_MAX], last_valueid = 0; zbx_agent_value_t values[ZBX_HISTORY_VALUES_MAX]; zbx_timespec_t unique_shift = {0, 0}; @@ -3593,8 +3593,7 @@ static int process_history_data_by_itemids(zbx_socket_t *sock, zbx_client_item_v total_num += read_num; - if (NULL != session) - session->last_valueid = values[values_num - 1].id; + last_valueid = values[values_num - 1].id; DCconfig_clean_items(items, errcodes, values_num); zbx_agent_values_clean(values, values_num); @@ -3603,6 +3602,17 @@ static int process_history_data_by_itemids(zbx_socket_t *sock, zbx_client_item_v break; } + if (NULL != session && 0 != last_valueid) + { + if (session->last_valueid > last_valueid) + { + zabbix_log(LOG_LEVEL_WARNING, "received id:" ZBX_FS_UI64 " is less than last id:" + ZBX_FS_UI64, last_valueid, session->last_valueid); + } + else + session->last_valueid = last_valueid; + } + zbx_free(errcodes); zbx_free(items); diff --git a/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java b/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java index 0fbb0080b5e..7106aa6389e 100644 --- a/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java +++ b/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java @@ -22,9 +22,9 @@ package com.zabbix.gateway; class GeneralInformation { static final String APPLICATION_NAME = "Zabbix Java Gateway"; - static final String REVISION_DATE = "25 January 2022"; + static final String REVISION_DATE = "31 January 2022"; static final String REVISION = "{ZABBIX_REVISION}"; - static final String VERSION = "5.4.10rc1"; + static final String VERSION = "5.4.11rc1"; static void printVersion() { diff --git a/src/zabbix_proxy/datasender/datasender.c b/src/zabbix_proxy/datasender/datasender.c index 967285f2e1f..249fb1e2f6b 100644 --- a/src/zabbix_proxy/datasender/datasender.c +++ b/src/zabbix_proxy/datasender/datasender.c @@ -184,9 +184,16 @@ static int proxy_data_sender(int *more, int now, int *hist_upload_state) reserved = j.buffer_size; zbx_json_free(&j); /* json buffer can be large, free as fast as possible */ + update_selfmon_counter(ZBX_PROCESS_STATE_IDLE); + /* retry till have a connection */ if (FAIL == connect_to_server(&sock, 600, CONFIG_PROXYDATA_FREQUENCY)) + { + update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); goto clean; + } + + update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); upload_state = put_data_to_server(&sock, &buffer, buffer_size, reserved, &error); get_hist_upload_state(sock.buffer, hist_upload_state); diff --git a/src/zabbix_proxy/proxyconfig/proxyconfig.c b/src/zabbix_proxy/proxyconfig/proxyconfig.c index 1fec32183e4..8f57ce27317 100644 --- a/src/zabbix_proxy/proxyconfig/proxyconfig.c +++ b/src/zabbix_proxy/proxyconfig/proxyconfig.c @@ -81,8 +81,15 @@ static void process_configuration_sync(size_t *data_size) reserved = j.buffer_size; zbx_json_free(&j); + update_selfmon_counter(ZBX_PROCESS_STATE_IDLE); + if (FAIL == connect_to_server(&sock, 600, CONFIG_PROXYCONFIG_RETRY)) /* retry till have a connection */ + { + update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); goto out; + } + + update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); if (SUCCEED != get_data_from_server(&sock, &buffer, buffer_size, reserved, &error)) { |