1// Copyright 2016 Circonus, Inc. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// OutlierReport API support - Fetch, Create, Update, Delete, and Search
6// See: https://login.circonus.com/resources/api/calls/report
7
8package api
9
10import (
11	"encoding/json"
12	"fmt"
13	"net/url"
14	"regexp"
15
16	"github.com/circonus-labs/circonus-gometrics/api/config"
17)
18
19// OutlierReport defines a outlier report. See https://login.circonus.com/resources/api/calls/report for more information.
20type OutlierReport struct {
21	CID              string   `json:"_cid,omitempty"`              // string
22	Config           string   `json:"config,omitempty"`            // string
23	Created          uint     `json:"_created,omitempty"`          // uint
24	CreatedBy        string   `json:"_created_by,omitempty"`       // string
25	LastModified     uint     `json:"_last_modified,omitempty"`    // uint
26	LastModifiedBy   string   `json:"_last_modified_by,omitempty"` // string
27	MetricClusterCID string   `json:"metric_cluster,omitempty"`    // st ring
28	Tags             []string `json:"tags,omitempty"`              // [] len >= 0
29	Title            string   `json:"title,omitempty"`             // string
30}
31
32// NewOutlierReport returns a new OutlierReport (with defaults, if applicable)
33func NewOutlierReport() *OutlierReport {
34	return &OutlierReport{}
35}
36
37// FetchOutlierReport retrieves outlier report with passed cid.
38func (a *API) FetchOutlierReport(cid CIDType) (*OutlierReport, error) {
39	if cid == nil || *cid == "" {
40		return nil, fmt.Errorf("Invalid outlier report CID [none]")
41	}
42
43	reportCID := string(*cid)
44
45	matched, err := regexp.MatchString(config.OutlierReportCIDRegex, reportCID)
46	if err != nil {
47		return nil, err
48	}
49	if !matched {
50		return nil, fmt.Errorf("Invalid outlier report CID [%s]", reportCID)
51	}
52
53	result, err := a.Get(reportCID)
54	if err != nil {
55		return nil, err
56	}
57
58	if a.Debug {
59		a.Log.Printf("[DEBUG] fetch outlier report, received JSON: %s", string(result))
60	}
61
62	report := &OutlierReport{}
63	if err := json.Unmarshal(result, report); err != nil {
64		return nil, err
65	}
66
67	return report, nil
68}
69
70// FetchOutlierReports retrieves all outlier reports available to API Token.
71func (a *API) FetchOutlierReports() (*[]OutlierReport, error) {
72	result, err := a.Get(config.OutlierReportPrefix)
73	if err != nil {
74		return nil, err
75	}
76
77	var reports []OutlierReport
78	if err := json.Unmarshal(result, &reports); err != nil {
79		return nil, err
80	}
81
82	return &reports, nil
83}
84
85// UpdateOutlierReport updates passed outlier report.
86func (a *API) UpdateOutlierReport(cfg *OutlierReport) (*OutlierReport, error) {
87	if cfg == nil {
88		return nil, fmt.Errorf("Invalid outlier report config [nil]")
89	}
90
91	reportCID := string(cfg.CID)
92
93	matched, err := regexp.MatchString(config.OutlierReportCIDRegex, reportCID)
94	if err != nil {
95		return nil, err
96	}
97	if !matched {
98		return nil, fmt.Errorf("Invalid outlier report CID [%s]", reportCID)
99	}
100
101	jsonCfg, err := json.Marshal(cfg)
102	if err != nil {
103		return nil, err
104	}
105
106	if a.Debug {
107		a.Log.Printf("[DEBUG] update outlier report, sending JSON: %s", string(jsonCfg))
108	}
109
110	result, err := a.Put(reportCID, jsonCfg)
111	if err != nil {
112		return nil, err
113	}
114
115	report := &OutlierReport{}
116	if err := json.Unmarshal(result, report); err != nil {
117		return nil, err
118	}
119
120	return report, nil
121}
122
123// CreateOutlierReport creates a new outlier report.
124func (a *API) CreateOutlierReport(cfg *OutlierReport) (*OutlierReport, error) {
125	if cfg == nil {
126		return nil, fmt.Errorf("Invalid outlier report config [nil]")
127	}
128
129	jsonCfg, err := json.Marshal(cfg)
130	if err != nil {
131		return nil, err
132	}
133
134	if a.Debug {
135		a.Log.Printf("[DEBUG] create outlier report, sending JSON: %s", string(jsonCfg))
136	}
137
138	result, err := a.Post(config.OutlierReportPrefix, jsonCfg)
139	if err != nil {
140		return nil, err
141	}
142
143	report := &OutlierReport{}
144	if err := json.Unmarshal(result, report); err != nil {
145		return nil, err
146	}
147
148	return report, nil
149}
150
151// DeleteOutlierReport deletes passed outlier report.
152func (a *API) DeleteOutlierReport(cfg *OutlierReport) (bool, error) {
153	if cfg == nil {
154		return false, fmt.Errorf("Invalid outlier report config [nil]")
155	}
156	return a.DeleteOutlierReportByCID(CIDType(&cfg.CID))
157}
158
159// DeleteOutlierReportByCID deletes outlier report with passed cid.
160func (a *API) DeleteOutlierReportByCID(cid CIDType) (bool, error) {
161	if cid == nil || *cid == "" {
162		return false, fmt.Errorf("Invalid outlier report CID [none]")
163	}
164
165	reportCID := string(*cid)
166
167	matched, err := regexp.MatchString(config.OutlierReportCIDRegex, reportCID)
168	if err != nil {
169		return false, err
170	}
171	if !matched {
172		return false, fmt.Errorf("Invalid outlier report CID [%s]", reportCID)
173	}
174
175	_, err = a.Delete(reportCID)
176	if err != nil {
177		return false, err
178	}
179
180	return true, nil
181}
182
183// SearchOutlierReports returns outlier report matching the
184// specified search query and/or filter. If nil is passed for
185// both parameters all outlier report will be returned.
186func (a *API) SearchOutlierReports(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]OutlierReport, error) {
187	q := url.Values{}
188
189	if searchCriteria != nil && *searchCriteria != "" {
190		q.Set("search", string(*searchCriteria))
191	}
192
193	if filterCriteria != nil && len(*filterCriteria) > 0 {
194		for filter, criteria := range *filterCriteria {
195			for _, val := range criteria {
196				q.Add(filter, val)
197			}
198		}
199	}
200
201	if q.Encode() == "" {
202		return a.FetchOutlierReports()
203	}
204
205	reqURL := url.URL{
206		Path:     config.OutlierReportPrefix,
207		RawQuery: q.Encode(),
208	}
209
210	result, err := a.Get(reqURL.String())
211	if err != nil {
212		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
213	}
214
215	var reports []OutlierReport
216	if err := json.Unmarshal(result, &reports); err != nil {
217		return nil, err
218	}
219
220	return &reports, nil
221}
222