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// Rule Set API support - Fetch, Create, Update, Delete, and Search
6// See: https://login.circonus.com/resources/api/calls/rule_set
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// RuleSetRule defines a ruleset rule
20type RuleSetRule struct {
21	Criteria          string      `json:"criteria"`                     // string
22	Severity          uint        `json:"severity"`                     // uint
23	Value             interface{} `json:"value"`                        // BUG doc: string, api: actual type returned switches based on Criteria
24	Wait              uint        `json:"wait"`                         // uint
25	WindowingDuration uint        `json:"windowing_duration,omitempty"` // uint
26	WindowingFunction *string     `json:"windowing_function,omitempty"` // string or null
27}
28
29// RuleSet defines a ruleset. See https://login.circonus.com/resources/api/calls/rule_set for more information.
30type RuleSet struct {
31	CheckCID      string             `json:"check"`            // string
32	CID           string             `json:"_cid,omitempty"`   // string
33	ContactGroups map[uint8][]string `json:"contact_groups"`   // [] len 5
34	Derive        *string            `json:"derive,omitempty"` // string or null
35	Link          *string            `json:"link"`             // string or null
36	MetricName    string             `json:"metric_name"`      // string
37	MetricTags    []string           `json:"metric_tags"`      // [] len >= 0
38	MetricType    string             `json:"metric_type"`      // string
39	Notes         *string            `json:"notes"`            // string or null
40	Parent        *string            `json:"parent,omitempty"` // string or null
41	Rules         []RuleSetRule      `json:"rules"`            // [] len >= 1
42	Tags          []string           `json:"tags"`             // [] len >= 0
43}
44
45// NewRuleSet returns a new RuleSet (with defaults if applicable)
46func NewRuleSet() *RuleSet {
47	return &RuleSet{}
48}
49
50// FetchRuleSet retrieves rule set with passed cid.
51func (a *API) FetchRuleSet(cid CIDType) (*RuleSet, error) {
52	if cid == nil || *cid == "" {
53		return nil, fmt.Errorf("Invalid rule set CID [none]")
54	}
55
56	rulesetCID := string(*cid)
57
58	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
59	if err != nil {
60		return nil, err
61	}
62	if !matched {
63		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
64	}
65
66	result, err := a.Get(rulesetCID)
67	if err != nil {
68		return nil, err
69	}
70
71	if a.Debug {
72		a.Log.Printf("[DEBUG] fetch rule set, received JSON: %s", string(result))
73	}
74
75	ruleset := &RuleSet{}
76	if err := json.Unmarshal(result, ruleset); err != nil {
77		return nil, err
78	}
79
80	return ruleset, nil
81}
82
83// FetchRuleSets retrieves all rule sets available to API Token.
84func (a *API) FetchRuleSets() (*[]RuleSet, error) {
85	result, err := a.Get(config.RuleSetPrefix)
86	if err != nil {
87		return nil, err
88	}
89
90	var rulesets []RuleSet
91	if err := json.Unmarshal(result, &rulesets); err != nil {
92		return nil, err
93	}
94
95	return &rulesets, nil
96}
97
98// UpdateRuleSet updates passed rule set.
99func (a *API) UpdateRuleSet(cfg *RuleSet) (*RuleSet, error) {
100	if cfg == nil {
101		return nil, fmt.Errorf("Invalid rule set config [nil]")
102	}
103
104	rulesetCID := string(cfg.CID)
105
106	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
107	if err != nil {
108		return nil, err
109	}
110	if !matched {
111		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
112	}
113
114	jsonCfg, err := json.Marshal(cfg)
115	if err != nil {
116		return nil, err
117	}
118
119	if a.Debug {
120		a.Log.Printf("[DEBUG] update rule set, sending JSON: %s", string(jsonCfg))
121	}
122
123	result, err := a.Put(rulesetCID, jsonCfg)
124	if err != nil {
125		return nil, err
126	}
127
128	ruleset := &RuleSet{}
129	if err := json.Unmarshal(result, ruleset); err != nil {
130		return nil, err
131	}
132
133	return ruleset, nil
134}
135
136// CreateRuleSet creates a new rule set.
137func (a *API) CreateRuleSet(cfg *RuleSet) (*RuleSet, error) {
138	if cfg == nil {
139		return nil, fmt.Errorf("Invalid rule set config [nil]")
140	}
141
142	jsonCfg, err := json.Marshal(cfg)
143	if err != nil {
144		return nil, err
145	}
146
147	if a.Debug {
148		a.Log.Printf("[DEBUG] create rule set, sending JSON: %s", string(jsonCfg))
149	}
150
151	resp, err := a.Post(config.RuleSetPrefix, jsonCfg)
152	if err != nil {
153		return nil, err
154	}
155
156	ruleset := &RuleSet{}
157	if err := json.Unmarshal(resp, ruleset); err != nil {
158		return nil, err
159	}
160
161	return ruleset, nil
162}
163
164// DeleteRuleSet deletes passed rule set.
165func (a *API) DeleteRuleSet(cfg *RuleSet) (bool, error) {
166	if cfg == nil {
167		return false, fmt.Errorf("Invalid rule set config [nil]")
168	}
169	return a.DeleteRuleSetByCID(CIDType(&cfg.CID))
170}
171
172// DeleteRuleSetByCID deletes rule set with passed cid.
173func (a *API) DeleteRuleSetByCID(cid CIDType) (bool, error) {
174	if cid == nil || *cid == "" {
175		return false, fmt.Errorf("Invalid rule set CID [none]")
176	}
177
178	rulesetCID := string(*cid)
179
180	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
181	if err != nil {
182		return false, err
183	}
184	if !matched {
185		return false, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
186	}
187
188	_, err = a.Delete(rulesetCID)
189	if err != nil {
190		return false, err
191	}
192
193	return true, nil
194}
195
196// SearchRuleSets returns rule sets matching the specified search
197// query and/or filter. If nil is passed for both parameters all
198// rule sets will be returned.
199func (a *API) SearchRuleSets(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]RuleSet, error) {
200	q := url.Values{}
201
202	if searchCriteria != nil && *searchCriteria != "" {
203		q.Set("search", string(*searchCriteria))
204	}
205
206	if filterCriteria != nil && len(*filterCriteria) > 0 {
207		for filter, criteria := range *filterCriteria {
208			for _, val := range criteria {
209				q.Add(filter, val)
210			}
211		}
212	}
213
214	if q.Encode() == "" {
215		return a.FetchRuleSets()
216	}
217
218	reqURL := url.URL{
219		Path:     config.RuleSetPrefix,
220		RawQuery: q.Encode(),
221	}
222
223	result, err := a.Get(reqURL.String())
224	if err != nil {
225		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
226	}
227
228	var rulesets []RuleSet
229	if err := json.Unmarshal(result, &rulesets); err != nil {
230		return nil, err
231	}
232
233	return &rulesets, nil
234}
235