diff --git a/README.md b/README.md index 6a8f2bd3..823fa346 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Usage of ./nginx-prometheus-exporter: * [Stream Server Zones](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_stream_server_zone). * [HTTP Upstreams](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_http_upstream). Note: for the `state` metric, the string values are converted to float64 using the following rule: `"up"` -> `1.0`, `"draining"` -> `2.0`, `"down"` -> `3.0`, `"unavail"` –> `4.0`, `"checking"` –> `5.0`, `"unhealthy"` -> `6.0`. * [Stream Upstreams](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_stream_upstream). Note: for the `state` metric, the string values are converted to float64 using the following rule: `"up"` -> `1.0`, `"down"` -> `3.0`, `"unavail"` –> `4.0`, `"checking"` –> `5.0`, `"unhealthy"` -> `6.0`. + * [Stream Zone Sync](http://nginx.org/en/docs/http/ngx_http_api_module.html#def_nginx_stream_zone_sync). * `nginxplus_up` -- shows the status of the last metric scrape: `1` for a successful scrape and `0` for a failed one. diff --git a/collector/nginx_plus.go b/collector/nginx_plus.go index 01524aa7..1a8bdfa5 100644 --- a/collector/nginx_plus.go +++ b/collector/nginx_plus.go @@ -4,7 +4,7 @@ import ( "log" "sync" - plusclient "github.com/nginxinc/nginx-plus-go-sdk/client" + plusclient "github.com/nginxinc/nginx-plus-go-client/client" "github.com/prometheus/client_golang/prometheus" ) @@ -18,6 +18,7 @@ type NginxPlusCollector struct { streamServerZoneMetrics map[string]*prometheus.Desc streamUpstreamMetrics map[string]*prometheus.Desc streamUpstreamServerMetrics map[string]*prometheus.Desc + streamZoneSyncMetrics map[string]*prometheus.Desc upMetric prometheus.Gauge mutex sync.Mutex } @@ -100,6 +101,15 @@ func NewNginxPlusCollector(nginxClient *plusclient.NginxClient, namespace string "health_checks_fails": newStreamUpstreamServerMetric(namespace, "health_checks_fails", "Failed health checks"), "health_checks_unhealthy": newStreamUpstreamServerMetric(namespace, "health_checks_unhealthy", "How many times the server became unhealthy (state 'unhealthy')"), }, + streamZoneSyncMetrics: map[string]*prometheus.Desc{ + "bytes_in": newStreamZoneSyncMetric(namespace, "bytes_in", "Bytes received by this node"), + "bytes_out": newStreamZoneSyncMetric(namespace, "bytes_out", "Bytes sent by this node"), + "msgs_in": newStreamZoneSyncMetric(namespace, "msgs_in", "Total messages received by this node"), + "msgs_out": newStreamZoneSyncMetric(namespace, "msgs_out", "Total messages sent by this node"), + "nodes_online": newStreamZoneSyncMetric(namespace, "nodes_online", "Number of peers this node is conected to"), + "records_pending": newStreamZoneSyncZoneMetric(namespace, "records_pending", "The number of records that need to be sent to the cluster"), + "records_total": newStreamZoneSyncZoneMetric(namespace, "records_total", "The total number of records stored in the shared memory zone"), + }, upMetric: newUpMetric(namespace), } } @@ -130,6 +140,9 @@ func (c *NginxPlusCollector) Describe(ch chan<- *prometheus.Desc) { for _, m := range c.streamUpstreamServerMetrics { ch <- m } + for _, m := range c.streamZoneSyncMetrics { + ch <- m + } } // Collect fetches metrics from NGINX Plus and sends them to the provided channel. @@ -289,6 +302,24 @@ func (c *NginxPlusCollector) Collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(c.streamUpstreamMetrics["zombies"], prometheus.GaugeValue, float64(upstream.Zombies), name) } + + for name, zone := range stats.StreamZoneSync.Zones { + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["records_pending"], + prometheus.GaugeValue, float64(zone.RecordsPending), name) + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["records_total"], + prometheus.GaugeValue, float64(zone.RecordsTotal), name) + } + + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["bytes_in"], + prometheus.CounterValue, float64(stats.StreamZoneSync.Status.BytesIn)) + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["bytes_out"], + prometheus.CounterValue, float64(stats.StreamZoneSync.Status.BytesOut)) + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["msgs_in"], + prometheus.CounterValue, float64(stats.StreamZoneSync.Status.MsgsIn)) + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["msgs_out"], + prometheus.CounterValue, float64(stats.StreamZoneSync.Status.MsgsOut)) + ch <- prometheus.MustNewConstMetric(c.streamZoneSyncMetrics["nodes_online"], + prometheus.GaugeValue, float64(stats.StreamZoneSync.Status.NodesOnline)) } var upstreamServerStates = map[string]float64{ @@ -323,3 +354,11 @@ func newUpstreamServerMetric(namespace string, metricName string, docString stri func newStreamUpstreamServerMetric(namespace string, metricName string, docString string) *prometheus.Desc { return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_upstream_server", metricName), docString, []string{"upstream", "server"}, nil) } + +func newStreamZoneSyncMetric(namespace string, metricName string, docString string) *prometheus.Desc { + return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_zone_sync_status", metricName), docString, nil, nil) +} + +func newStreamZoneSyncZoneMetric(namespace string, metricName string, docString string) *prometheus.Desc { + return prometheus.NewDesc(prometheus.BuildFQName(namespace, "stream_zone_sync_zone", metricName), docString, []string{"zone"}, nil) +} diff --git a/exporter.go b/exporter.go index f2b991a0..30629da7 100644 --- a/exporter.go +++ b/exporter.go @@ -12,7 +12,7 @@ import ( "syscall" "time" - plusclient "github.com/nginxinc/nginx-plus-go-sdk/client" + plusclient "github.com/nginxinc/nginx-plus-go-client/client" "github.com/nginxinc/nginx-prometheus-exporter/client" "github.com/nginxinc/nginx-prometheus-exporter/collector" "github.com/prometheus/client_golang/prometheus" diff --git a/go.mod b/go.mod index f2d75fa3..f9d79cec 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module github.com/nginxinc/nginx-prometheus-exporter go 1.12 require ( - github.com/nginxinc/nginx-plus-go-sdk v0.0.0-20180910131828-47154e1ef115 + github.com/nginxinc/nginx-plus-go-client v0.0.0-20190529112308-8f20f677a8bf github.com/prometheus/client_golang v0.9.2 ) diff --git a/go.sum b/go.sum index ca584cd5..49c394f3 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,14 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/nginxinc/nginx-plus-go-sdk v0.0.0-20180910131828-47154e1ef115 h1:CWauBkD0d1oC7C4sZ+MeggmcYMVK0WHQZZFjsys0Cq0= -github.com/nginxinc/nginx-plus-go-sdk v0.0.0-20180910131828-47154e1ef115/go.mod h1:QqHe+Px9tTm7GOQUBDQGDQHA9m/J+J3JjHbxgri5gSw= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190326123225-e0cdc4be0c7f h1:3DdSFnaXSvhgn9RhiptJiudBHmFq+wDRccrJwhrwHlg= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190522143815-28e3fc49525c h1:xyY2/MuxVbzzEXAJkaFWERM3RtCaz/IX/jBOJZkZVc4= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190522143815-28e3fc49525c/go.mod h1:DBAmdDP71tOhgFPdCMVusegzdKmLVpVL0nVcMX17pbY= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190524095408-9fb6bf19a64e h1:7DbTRinSESf1WTnnGxoD7o0bvnFHIxVINTaMNYVFiHo= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190524144844-4d90184fc765 h1:SwxKOmnP+AELWdMDac0N7x7dN1vxoKjK5i2x2qYjOGQ= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190524144844-4d90184fc765/go.mod h1:DBAmdDP71tOhgFPdCMVusegzdKmLVpVL0nVcMX17pbY= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190529112308-8f20f677a8bf h1:QFUdFoJTsB60JpskBNicEQhu220DEL7UV8SJKUwdi3o= +github.com/nginxinc/nginx-plus-go-client v0.0.0-20190529112308-8f20f677a8bf/go.mod h1:DBAmdDP71tOhgFPdCMVusegzdKmLVpVL0nVcMX17pbY= github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= diff --git a/vendor/github.com/nginxinc/nginx-plus-go-sdk/LICENSE b/vendor/github.com/nginxinc/nginx-plus-go-client/LICENSE similarity index 100% rename from vendor/github.com/nginxinc/nginx-plus-go-sdk/LICENSE rename to vendor/github.com/nginxinc/nginx-plus-go-client/LICENSE diff --git a/vendor/github.com/nginxinc/nginx-plus-go-sdk/client/nginx.go b/vendor/github.com/nginxinc/nginx-plus-go-client/client/nginx.go similarity index 69% rename from vendor/github.com/nginxinc/nginx-plus-go-sdk/client/nginx.go rename to vendor/github.com/nginxinc/nginx-plus-go-client/client/nginx.go index 07fdce40..e75b5d22 100644 --- a/vendor/github.com/nginxinc/nginx-plus-go-sdk/client/nginx.go +++ b/vendor/github.com/nginxinc/nginx-plus-go-client/client/nginx.go @@ -10,9 +10,12 @@ import ( ) // APIVersion is a version of NGINX Plus API. -const APIVersion = 2 +const APIVersion = 4 -const streamNotConfiguredCode = "StreamNotConfigured" +const pathNotFoundCode = "PathNotFound" + +const streamContext = true +const httpContext = false // NginxClient lets you access NGINX Plus API. type NginxClient struct { @@ -41,16 +44,14 @@ type StreamUpstreamServer struct { } type apiErrorResponse struct { - Path string - Method string Error apiError RequestID string `json:"request_id"` Href string } func (resp *apiErrorResponse) toString() string { - return fmt.Sprintf("path=%v; method=%v; error.status=%v; error.text=%v; error.code=%v; request_id=%v; href=%v", - resp.Path, resp.Method, resp.Error.Status, resp.Error.Text, resp.Error.Code, resp.RequestID, resp.Href) + return fmt.Sprintf("error.status=%v; error.text=%v; error.code=%v; request_id=%v; href=%v", + resp.Error.Status, resp.Error.Text, resp.Error.Code, resp.RequestID, resp.Href) } type apiError struct { @@ -70,7 +71,7 @@ func (internalError *internalError) Error() string { } // Wrap is a way of including current context while preserving previous error information, -// similar to `return fmt.Errof("error doing foo, err: %v", err)` but for our internalError type. +// similar to `return fmt.Errorf("error doing foo, err: %v", err)` but for our internalError type. func (internalError *internalError) Wrap(err string) *internalError { internalError.err = fmt.Sprintf("%v. %v", err, internalError.err) return internalError @@ -79,6 +80,7 @@ func (internalError *internalError) Wrap(err string) *internalError { // Stats represents NGINX Plus stats fetched from the NGINX Plus API. // https://nginx.org/en/docs/http/ngx_http_api_module.html type Stats struct { + NginxInfo NginxInfo Connections Connections HTTPRequests HTTPRequests SSL SSL @@ -86,6 +88,19 @@ type Stats struct { Upstreams Upstreams StreamServerZones StreamServerZones StreamUpstreams StreamUpstreams + StreamZoneSync StreamZoneSync +} + +// NginxInfo contains general information about NGINX Plus. +type NginxInfo struct { + Version string + Build string + Address string + Generation uint64 + LoadTimestamp string `json:"load_timestamp"` + Timestamp string + ProcessID uint64 `json:"pid"` + ParentProcessID uint64 `json:"ppid"` } // Connections represents connection related stats. @@ -135,6 +150,27 @@ type StreamServerZone struct { Sent uint64 } +// StreamZoneSync represents the sync information per each shared memory zone and the sync information per node in a cluster +type StreamZoneSync struct { + Zones map[string]SyncZone + Status StreamZoneSyncStatus +} + +// SyncZone represents the syncronization status of a shared memory zone +type SyncZone struct { + RecordsPending uint64 `json:"records_pending"` + RecordsTotal uint64 `json:"records_total"` +} + +// StreamZoneSyncStatus represents the status of a shared memory zone +type StreamZoneSyncStatus struct { + BytesIn uint64 `json:"bytes_in"` + MsgsIn uint64 `json:"msgs_in"` + MsgsOut uint64 `json:"msgs_out"` + BytesOut uint64 `json:"bytes_out"` + NodesOnline uint64 `json:"nodes_online"` +} + // Responses represents HTTP response related stats. type Responses struct { Responses1xx uint64 `json:"1xx"` @@ -243,7 +279,6 @@ type HealthChecks struct { // NewNginxClient creates an NginxClient. func NewNginxClient(httpClient *http.Client, apiEndpoint string) (*NginxClient, error) { versions, err := getAPIVersions(httpClient, apiEndpoint) - if err != nil { return nil, fmt.Errorf("error accessing the API: %v", err) } @@ -332,7 +367,6 @@ func (client *NginxClient) GetHTTPServers(upstream string) ([]UpstreamServer, er var servers []UpstreamServer err := client.get(path, &servers) - if err != nil { return nil, fmt.Errorf("failed to get the HTTP servers of upstream %v: %v", upstream, err) } @@ -343,7 +377,6 @@ func (client *NginxClient) GetHTTPServers(upstream string) ([]UpstreamServer, er // AddHTTPServer adds the server to the upstream. func (client *NginxClient) AddHTTPServer(upstream string, server UpstreamServer) error { id, err := client.getIDOfHTTPServer(upstream, server.Server) - if err != nil { return fmt.Errorf("failed to add %v server to %v upstream: %v", server.Server, upstream, err) } @@ -371,8 +404,7 @@ func (client *NginxClient) DeleteHTTPServer(upstream string, server string) erro } path := fmt.Sprintf("http/upstreams/%v/servers/%v", upstream, id) - err = client.delete(path) - + err = client.delete(path, http.StatusOK) if err != nil { return fmt.Errorf("failed to remove %v server from %v upstream: %v", server, upstream, err) } @@ -500,7 +532,7 @@ func (client *NginxClient) post(path string, input interface{}) error { return nil } -func (client *NginxClient) delete(path string) error { +func (client *NginxClient) delete(path string, expectedStatusCode int) error { path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, APIVersion, path) req, err := http.NewRequest(http.MethodDelete, path, nil) @@ -514,10 +546,37 @@ func (client *NginxClient) delete(path string) error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { + if resp.StatusCode != expectedStatusCode { return createResponseMismatchError(resp.Body).Wrap(fmt.Sprintf( "failed to complete delete request: expected %v response, got %v", - http.StatusOK, resp.StatusCode)) + expectedStatusCode, resp.StatusCode)) + } + return nil +} + +func (client *NginxClient) patch(path string, input interface{}) error { + path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, APIVersion, path) + + jsonInput, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to marshall input: %v", err) + } + + req, err := http.NewRequest(http.MethodPatch, path, bytes.NewBuffer(jsonInput)) + if err != nil { + return fmt.Errorf("failed to create a patch request: %v", err) + } + + resp, err := client.httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to create patch request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusNoContent { + return createResponseMismatchError(resp.Body).Wrap(fmt.Sprintf( + "failed to complete patch request: expected %v response, got %v", + http.StatusNoContent, resp.StatusCode)) } return nil } @@ -534,18 +593,15 @@ func (client *NginxClient) GetStreamServers(upstream string) ([]StreamUpstreamSe var servers []StreamUpstreamServer err := client.get(path, &servers) - if err != nil { return nil, fmt.Errorf("failed to get stream servers of upstream server %v: %v", upstream, err) } - return servers, nil } // AddStreamServer adds the stream server to the upstream. func (client *NginxClient) AddStreamServer(upstream string, server StreamUpstreamServer) error { id, err := client.getIDOfStreamServer(upstream, server.Server) - if err != nil { return fmt.Errorf("failed to add %v stream server to %v upstream: %v", server.Server, upstream, err) } @@ -555,11 +611,9 @@ func (client *NginxClient) AddStreamServer(upstream string, server StreamUpstrea path := fmt.Sprintf("stream/upstreams/%v/servers/", upstream) err = client.post(path, &server) - if err != nil { return fmt.Errorf("failed to add %v stream server to %v upstream: %v", server.Server, upstream, err) } - return nil } @@ -574,12 +628,10 @@ func (client *NginxClient) DeleteStreamServer(upstream string, server string) er } path := fmt.Sprintf("stream/upstreams/%v/servers/%v", upstream, id) - err = client.delete(path) - + err = client.delete(path, http.StatusOK) if err != nil { return fmt.Errorf("failed to remove %v stream server from %v upstream: %v", server, upstream, err) } - return nil } @@ -658,6 +710,11 @@ func determineStreamUpdates(updatedServers []StreamUpstreamServer, nginxServers // GetStats gets connection, request, ssl, zone, stream zone, upstream and stream upstream related stats from the NGINX Plus API. func (client *NginxClient) GetStats() (*Stats, error) { + info, err := client.getNginxInfo() + if err != nil { + return nil, fmt.Errorf("failed to get stats %v", err) + } + cons, err := client.getConnections() if err != nil { return nil, fmt.Errorf("failed to get stats: %v", err) @@ -693,7 +750,13 @@ func (client *NginxClient) GetStats() (*Stats, error) { return nil, fmt.Errorf("failed to get stats: %v", err) } + streamZoneSync, err := client.getStreamZoneSync() + if err != nil { + return nil, fmt.Errorf("failed to get stats: %v", err) + } + return &Stats{ + NginxInfo: *info, Connections: *cons, HTTPRequests: *requests, SSL: *ssl, @@ -701,9 +764,19 @@ func (client *NginxClient) GetStats() (*Stats, error) { StreamServerZones: *streamZones, Upstreams: *upstreams, StreamUpstreams: *streamUpstreams, + StreamZoneSync: *streamZoneSync, }, nil } +func (client *NginxClient) getNginxInfo() (*NginxInfo, error) { + var info NginxInfo + err := client.get("nginx", &info) + if err != nil { + return nil, fmt.Errorf("failed to get info: %v", err) + } + return &info, nil +} + func (client *NginxClient) getConnections() (*Connections, error) { var cons Connections err := client.get("connections", &cons) @@ -715,12 +788,10 @@ func (client *NginxClient) getConnections() (*Connections, error) { func (client *NginxClient) getHTTPRequests() (*HTTPRequests, error) { var requests HTTPRequests - err := client.get("http/requests", &requests) if err != nil { return nil, fmt.Errorf("failed to get http requests: %v", err) } - return &requests, nil } @@ -747,7 +818,7 @@ func (client *NginxClient) getStreamServerZones() (*StreamServerZones, error) { err := client.get("stream/server_zones", &zones) if err != nil { if err, ok := err.(*internalError); ok { - if err.Code == streamNotConfiguredCode { + if err.Code == pathNotFoundCode { return &zones, nil } } @@ -770,7 +841,7 @@ func (client *NginxClient) getStreamUpstreams() (*StreamUpstreams, error) { err := client.get("stream/upstreams", &upstreams) if err != nil { if err, ok := err.(*internalError); ok { - if err.Code == streamNotConfiguredCode { + if err.Code == pathNotFoundCode { return &upstreams, nil } } @@ -778,3 +849,194 @@ func (client *NginxClient) getStreamUpstreams() (*StreamUpstreams, error) { } return &upstreams, nil } + +func (client *NginxClient) getStreamZoneSync() (*StreamZoneSync, error) { + var streamZoneSync StreamZoneSync + err := client.get("stream/zone_sync", &streamZoneSync) + if err != nil { + if err, ok := err.(*internalError); ok { + + if err.Code == pathNotFoundCode { + return &streamZoneSync, nil + } + } + return nil, fmt.Errorf("failed to get stream zone sync: %v", err) + } + + return &streamZoneSync, err +} + +// KeyValPairs are the key-value pairs stored in a zone. +type KeyValPairs map[string]string + +// KeyValPairsByZone are the KeyValPairs for all zones, by zone name. +type KeyValPairsByZone map[string]KeyValPairs + +// GetKeyValPairs fetches key/value pairs for a given HTTP zone. +func (client *NginxClient) GetKeyValPairs(zone string) (KeyValPairs, error) { + return client.getKeyValPairs(zone, httpContext) +} + +// GetStreamKeyValPairs fetches key/value pairs for a given Stream zone. +func (client *NginxClient) GetStreamKeyValPairs(zone string) (KeyValPairs, error) { + return client.getKeyValPairs(zone, streamContext) +} + +func (client *NginxClient) getKeyValPairs(zone string, stream bool) (KeyValPairs, error) { + base := "http" + if stream { + base = "stream" + } + if zone == "" { + return nil, fmt.Errorf("zone required") + } + + path := fmt.Sprintf("%v/keyvals/%v", base, zone) + var keyValPairs KeyValPairs + err := client.get(path, &keyValPairs) + if err != nil { + return nil, fmt.Errorf("failed to get keyvals for %v/%v zone: %v", base, zone, err) + } + return keyValPairs, nil +} + +// GetAllKeyValPairs fetches all key/value pairs for all HTTP zones. +func (client *NginxClient) GetAllKeyValPairs() (KeyValPairsByZone, error) { + return client.getAllKeyValPairs(httpContext) +} + +// GetAllStreamKeyValPairs fetches all key/value pairs for all Stream zones. +func (client *NginxClient) GetAllStreamKeyValPairs() (KeyValPairsByZone, error) { + return client.getAllKeyValPairs(streamContext) +} + +func (client *NginxClient) getAllKeyValPairs(stream bool) (KeyValPairsByZone, error) { + base := "http" + if stream { + base = "stream" + } + + path := fmt.Sprintf("%v/keyvals", base) + var keyValPairsByZone KeyValPairsByZone + err := client.get(path, &keyValPairsByZone) + if err != nil { + return nil, fmt.Errorf("failed to get keyvals for all %v zones: %v", base, err) + } + return keyValPairsByZone, nil +} + +// AddKeyValPair adds a new key/value pair to a given HTTP zone. +func (client *NginxClient) AddKeyValPair(zone string, key string, val string) error { + return client.addKeyValPair(zone, key, val, httpContext) +} + +// AddStreamKeyValPair adds a new key/value pair to a given Stream zone. +func (client *NginxClient) AddStreamKeyValPair(zone string, key string, val string) error { + return client.addKeyValPair(zone, key, val, streamContext) +} + +func (client *NginxClient) addKeyValPair(zone string, key string, val string, stream bool) error { + base := "http" + if stream { + base = "stream" + } + if zone == "" { + return fmt.Errorf("zone required") + } + + path := fmt.Sprintf("%v/keyvals/%v", base, zone) + input := KeyValPairs{key: val} + err := client.post(path, &input) + if err != nil { + return fmt.Errorf("failed to add key value pair for %v/%v zone: %v", base, zone, err) + } + return nil +} + +// ModifyKeyValPair modifies the value of an existing key in a given HTTP zone. +func (client *NginxClient) ModifyKeyValPair(zone string, key string, val string) error { + return client.modifyKeyValPair(zone, key, val, httpContext) +} + +// ModifyStreamKeyValPair modifies the value of an existing key in a given Stream zone. +func (client *NginxClient) ModifyStreamKeyValPair(zone string, key string, val string) error { + return client.modifyKeyValPair(zone, key, val, streamContext) +} + +func (client *NginxClient) modifyKeyValPair(zone string, key string, val string, stream bool) error { + base := "http" + if stream { + base = "stream" + } + if zone == "" { + return fmt.Errorf("zone required") + } + + path := fmt.Sprintf("%v/keyvals/%v", base, zone) + input := KeyValPairs{key: val} + err := client.patch(path, &input) + if err != nil { + return fmt.Errorf("failed to update key value pair for %v/%v zone: %v", base, zone, err) + } + return nil +} + +// DeleteKeyValuePair deletes the key/value pair for a key in a given HTTP zone. +func (client *NginxClient) DeleteKeyValuePair(zone string, key string) error { + return client.deleteKeyValuePair(zone, key, httpContext) +} + +// DeleteStreamKeyValuePair deletes the key/value pair for a key in a given Stream zone. +func (client *NginxClient) DeleteStreamKeyValuePair(zone string, key string) error { + return client.deleteKeyValuePair(zone, key, streamContext) +} + +// To delete a key/value pair you set the value to null via the API, +// then NGINX+ will delete the key. +func (client *NginxClient) deleteKeyValuePair(zone string, key string, stream bool) error { + base := "http" + if stream { + base = "stream" + } + if zone == "" { + return fmt.Errorf("zone required") + } + + // map[string]string can't have a nil value so we use a different type here. + keyval := make(map[string]interface{}) + keyval[key] = nil + + path := fmt.Sprintf("%v/keyvals/%v", base, zone) + err := client.patch(path, &keyval) + if err != nil { + return fmt.Errorf("failed to remove key values pair for %v/%v zone: %v", base, zone, err) + } + return nil +} + +// DeleteKeyValPairs deletes all the key-value pairs in a given HTTP zone. +func (client *NginxClient) DeleteKeyValPairs(zone string) error { + return client.deleteKeyValPairs(zone, httpContext) +} + +// DeleteStreamKeyValPairs deletes all the key-value pairs in a given Stream zone. +func (client *NginxClient) DeleteStreamKeyValPairs(zone string) error { + return client.deleteKeyValPairs(zone, streamContext) +} + +func (client *NginxClient) deleteKeyValPairs(zone string, stream bool) error { + base := "http" + if stream { + base = "stream" + } + if zone == "" { + return fmt.Errorf("zone required") + } + + path := fmt.Sprintf("%v/keyvals/%v", base, zone) + err := client.delete(path, http.StatusNoContent) + if err != nil { + return fmt.Errorf("failed to remove all key value pairs for %v/%v zone: %v", base, zone, err) + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index a5283167..46f9d635 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -4,8 +4,8 @@ github.com/beorn7/perks/quantile github.com/golang/protobuf/proto # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil -# github.com/nginxinc/nginx-plus-go-sdk v0.0.0-20180910131828-47154e1ef115 -github.com/nginxinc/nginx-plus-go-sdk/client +# github.com/nginxinc/nginx-plus-go-client v0.0.0-20190529112308-8f20f677a8bf +github.com/nginxinc/nginx-plus-go-client/client # github.com/prometheus/client_golang v0.9.2 github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/promhttp