From 2d0f83b5478aa014ff7eb20f1963c297874fd6db Mon Sep 17 00:00:00 2001 From: Vighneswar Rao Bojja Date: Mon, 16 Sep 2019 19:31:49 +0530 Subject: [PATCH] Support location zones and resolver metrics in go client --- Makefile | 2 +- client/nginx.go | 76 +++++++++++++++++++++++++++++++++++++++++++- docker/nginx.conf | 2 +- docker/test.conf | 1 + tests/client_test.go | 16 ++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 92c6f67e..268883c1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NGINX_PLUS_VERSION=18-1 +NGINX_PLUS_VERSION=19-1 NGINX_IMAGE=nginxplus:$(NGINX_PLUS_VERSION) test: docker-build run-nginx-plus test-run configure-no-stream-block test-run-no-stream-block clean diff --git a/client/nginx.go b/client/nginx.go index 745fa399..42bb92f8 100644 --- a/client/nginx.go +++ b/client/nginx.go @@ -10,7 +10,7 @@ import ( ) // APIVersion is a version of NGINX Plus API. -const APIVersion = 4 +const APIVersion = 5 const pathNotFoundCode = "PathNotFound" @@ -101,6 +101,8 @@ type Stats struct { StreamServerZones StreamServerZones StreamUpstreams StreamUpstreams StreamZoneSync *StreamZoneSync + LocationZones LocationZones + Resolvers Resolvers } // NginxInfo contains general information about NGINX Plus. @@ -288,6 +290,46 @@ type HealthChecks struct { LastPassed bool `json:"last_passed"` } +// LocationZones represents location_zones related stats +type LocationZones map[string]LocationZone + +// Resolvers represents resolvers related stats +type Resolvers map[string]Resolver + +// LocationZone represents location_zones related stats +type LocationZone struct { + Requests int64 + Responses Responses + Discarded int64 + Received int64 + Sent int64 +} + +// Resolver represents resolvers related stats +type Resolver struct { + Requests ResolverRequests `json:"requests"` + Responses ResolverResponses `json:"responses"` +} + +// ResolverRequests represents resolver requests +type ResolverRequests struct { + Name int64 + Srv int64 + Addr int64 +} + +// ResolverResponses represents resolver responses +type ResolverResponses struct { + Noerror int64 + Formerr int64 + Servfail int64 + Nxdomain int64 + Notimp int64 + Refused int64 + Timedout int64 + Unknown int64 +} + // NewNginxClient creates an NginxClient. func NewNginxClient(httpClient *http.Client, apiEndpoint string) (*NginxClient, error) { versions, err := getAPIVersions(httpClient, apiEndpoint) @@ -767,6 +809,16 @@ func (client *NginxClient) GetStats() (*Stats, error) { return nil, fmt.Errorf("failed to get stats: %v", err) } + locationZones, err := client.getLocationZones() + if err != nil { + return nil, fmt.Errorf("failed to get stats: %v", err) + } + + resolvers, err := client.getResolvers() + if err != nil { + return nil, fmt.Errorf("failed to get stats: %v", err) + } + return &Stats{ NginxInfo: *info, Connections: *cons, @@ -777,6 +829,8 @@ func (client *NginxClient) GetStats() (*Stats, error) { Upstreams: *upstreams, StreamUpstreams: *streamUpstreams, StreamZoneSync: streamZoneSync, + LocationZones: *locationZones, + Resolvers: *resolvers, }, nil } @@ -877,6 +931,26 @@ func (client *NginxClient) getStreamZoneSync() (*StreamZoneSync, error) { return &streamZoneSync, err } +func (client *NginxClient) getLocationZones() (*LocationZones, error) { + var locationZones LocationZones + err := client.get("http/location_zones", &locationZones) + if err != nil { + return nil, fmt.Errorf("failed to get location zones: %v", err) + } + + return &locationZones, err +} + +func (client *NginxClient) getResolvers() (*Resolvers, error) { + var resolvers Resolvers + err := client.get("resolvers", &resolvers) + if err != nil { + return nil, fmt.Errorf("failed to get resolvers: %v", err) + } + + return &resolvers, err +} + // KeyValPairs are the key-value pairs stored in a zone. type KeyValPairs map[string]string diff --git a/docker/nginx.conf b/docker/nginx.conf index 2925e8ad..548c69ba 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -50,7 +50,7 @@ stream { health_check interval=10 fails=3 passes=1; } - resolver 127.0.0.11 valid=5s; + resolver 127.0.0.11 valid=5s status_zone=resolver_test; server { listen 7777; diff --git a/docker/test.conf b/docker/test.conf index 34940788..4d985053 100644 --- a/docker/test.conf +++ b/docker/test.conf @@ -10,6 +10,7 @@ server { } location /api { + status_zone location_test; api write=on; } diff --git a/tests/client_test.go b/tests/client_test.go index f95084b4..a53b021f 100644 --- a/tests/client_test.go +++ b/tests/client_test.go @@ -14,6 +14,8 @@ const ( upstream = "test" streamUpstream = "stream_test" streamZoneSync = "zone_test_sync" + locationZone = "location_test" + resolverMetric = "resolver_test" ) var defaultMaxFails = 1 @@ -483,6 +485,20 @@ func TestStats(t *testing.T) { } else { t.Errorf("Upstream 'test' not found") } + if locZones, ok := stats.LocationZones[locationZone]; ok { + if locZones.Requests < 1 { + t.Errorf("LocationZone stats missing: %v", locZones.Requests) + } + } else { + t.Errorf("LocationZone %v not found", locationZone) + } + if resolver, ok := stats.Resolvers[resolverMetric]; ok { + if resolver.Requests.Name < 1 { + t.Errorf("Resolvers stats missing: %v", resolver.Requests) + } + } else { + t.Errorf("Resolver %v not found", resolverMetric) + } // cleanup upstream servers _, _, err = c.UpdateHTTPServers(upstream, []client.UpstreamServer{})