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// Check bundle API support - Fetch, Create, Update, Delete, and Search 6// See: https://login.circonus.com/resources/api/calls/check_bundle 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// CheckBundleMetric individual metric configuration 20type CheckBundleMetric struct { 21 Name string `json:"name"` // string 22 Result *string `json:"result,omitempty"` // string or null, NOTE not settable - return/information value only 23 Status string `json:"status,omitempty"` // string 24 Tags []string `json:"tags"` // [] len >= 0 25 Type string `json:"type"` // string 26 Units *string `json:"units,omitempty"` // string or null 27 28} 29 30// CheckBundleConfig contains the check type specific configuration settings 31// as k/v pairs (see https://login.circonus.com/resources/api/calls/check_bundle 32// for the specific settings available for each distinct check type) 33type CheckBundleConfig map[config.Key]string 34 35// CheckBundle defines a check bundle. See https://login.circonus.com/resources/api/calls/check_bundle for more information. 36type CheckBundle struct { 37 Brokers []string `json:"brokers"` // [] len >= 0 38 Checks []string `json:"_checks,omitempty"` // [] len >= 0 39 CheckUUIDs []string `json:"_check_uuids,omitempty"` // [] len >= 0 40 CID string `json:"_cid,omitempty"` // string 41 Config CheckBundleConfig `json:"config"` // NOTE contents of config are check type specific, map len >= 0 42 Created uint `json:"_created,omitempty"` // uint 43 DisplayName string `json:"display_name"` // string 44 LastModifedBy string `json:"_last_modifed_by,omitempty"` // string 45 LastModified uint `json:"_last_modified,omitempty"` // uint 46 MetricLimit int `json:"metric_limit,omitempty"` // int 47 Metrics []CheckBundleMetric `json:"metrics"` // [] >= 0 48 Notes *string `json:"notes,omitempty"` // string or null 49 Period uint `json:"period,omitempty"` // uint 50 ReverseConnectURLs []string `json:"_reverse_connection_urls,omitempty"` // [] len >= 0 51 Status string `json:"status,omitempty"` // string 52 Tags []string `json:"tags,omitempty"` // [] len >= 0 53 Target string `json:"target"` // string 54 Timeout float32 `json:"timeout,omitempty"` // float32 55 Type string `json:"type"` // string 56} 57 58// NewCheckBundle returns new CheckBundle (with defaults, if applicable) 59func NewCheckBundle() *CheckBundle { 60 return &CheckBundle{ 61 Config: make(CheckBundleConfig, config.DefaultConfigOptionsSize), 62 MetricLimit: config.DefaultCheckBundleMetricLimit, 63 Period: config.DefaultCheckBundlePeriod, 64 Timeout: config.DefaultCheckBundleTimeout, 65 Status: config.DefaultCheckBundleStatus, 66 } 67} 68 69// FetchCheckBundle retrieves check bundle with passed cid. 70func (a *API) FetchCheckBundle(cid CIDType) (*CheckBundle, error) { 71 if cid == nil || *cid == "" { 72 return nil, fmt.Errorf("Invalid check bundle CID [none]") 73 } 74 75 bundleCID := string(*cid) 76 77 matched, err := regexp.MatchString(config.CheckBundleCIDRegex, bundleCID) 78 if err != nil { 79 return nil, err 80 } 81 if !matched { 82 return nil, fmt.Errorf("Invalid check bundle CID [%v]", bundleCID) 83 } 84 85 result, err := a.Get(bundleCID) 86 if err != nil { 87 return nil, err 88 } 89 90 if a.Debug { 91 a.Log.Printf("[DEBUG] fetch check bundle, received JSON: %s", string(result)) 92 } 93 94 checkBundle := &CheckBundle{} 95 if err := json.Unmarshal(result, checkBundle); err != nil { 96 return nil, err 97 } 98 99 return checkBundle, nil 100} 101 102// FetchCheckBundles retrieves all check bundles available to the API Token. 103func (a *API) FetchCheckBundles() (*[]CheckBundle, error) { 104 result, err := a.Get(config.CheckBundlePrefix) 105 if err != nil { 106 return nil, err 107 } 108 109 var checkBundles []CheckBundle 110 if err := json.Unmarshal(result, &checkBundles); err != nil { 111 return nil, err 112 } 113 114 return &checkBundles, nil 115} 116 117// UpdateCheckBundle updates passed check bundle. 118func (a *API) UpdateCheckBundle(cfg *CheckBundle) (*CheckBundle, error) { 119 if cfg == nil { 120 return nil, fmt.Errorf("Invalid check bundle config [nil]") 121 } 122 123 bundleCID := string(cfg.CID) 124 125 matched, err := regexp.MatchString(config.CheckBundleCIDRegex, bundleCID) 126 if err != nil { 127 return nil, err 128 } 129 if !matched { 130 return nil, fmt.Errorf("Invalid check bundle CID [%s]", bundleCID) 131 } 132 133 jsonCfg, err := json.Marshal(cfg) 134 if err != nil { 135 return nil, err 136 } 137 138 if a.Debug { 139 a.Log.Printf("[DEBUG] update check bundle, sending JSON: %s", string(jsonCfg)) 140 } 141 142 result, err := a.Put(bundleCID, jsonCfg) 143 if err != nil { 144 return nil, err 145 } 146 147 checkBundle := &CheckBundle{} 148 if err := json.Unmarshal(result, checkBundle); err != nil { 149 return nil, err 150 } 151 152 return checkBundle, nil 153} 154 155// CreateCheckBundle creates a new check bundle (check). 156func (a *API) CreateCheckBundle(cfg *CheckBundle) (*CheckBundle, error) { 157 if cfg == nil { 158 return nil, fmt.Errorf("Invalid check bundle config [nil]") 159 } 160 161 jsonCfg, err := json.Marshal(cfg) 162 if err != nil { 163 return nil, err 164 } 165 166 if a.Debug { 167 a.Log.Printf("[DEBUG] create check bundle, sending JSON: %s", string(jsonCfg)) 168 } 169 170 result, err := a.Post(config.CheckBundlePrefix, jsonCfg) 171 if err != nil { 172 return nil, err 173 } 174 175 checkBundle := &CheckBundle{} 176 if err := json.Unmarshal(result, checkBundle); err != nil { 177 return nil, err 178 } 179 180 return checkBundle, nil 181} 182 183// DeleteCheckBundle deletes passed check bundle. 184func (a *API) DeleteCheckBundle(cfg *CheckBundle) (bool, error) { 185 if cfg == nil { 186 return false, fmt.Errorf("Invalid check bundle config [nil]") 187 } 188 return a.DeleteCheckBundleByCID(CIDType(&cfg.CID)) 189} 190 191// DeleteCheckBundleByCID deletes check bundle with passed cid. 192func (a *API) DeleteCheckBundleByCID(cid CIDType) (bool, error) { 193 194 if cid == nil || *cid == "" { 195 return false, fmt.Errorf("Invalid check bundle CID [none]") 196 } 197 198 bundleCID := string(*cid) 199 200 matched, err := regexp.MatchString(config.CheckBundleCIDRegex, bundleCID) 201 if err != nil { 202 return false, err 203 } 204 if !matched { 205 return false, fmt.Errorf("Invalid check bundle CID [%v]", bundleCID) 206 } 207 208 _, err = a.Delete(bundleCID) 209 if err != nil { 210 return false, err 211 } 212 213 return true, nil 214} 215 216// SearchCheckBundles returns check bundles matching the specified 217// search query and/or filter. If nil is passed for both parameters 218// all check bundles will be returned. 219func (a *API) SearchCheckBundles(searchCriteria *SearchQueryType, filterCriteria *map[string][]string) (*[]CheckBundle, error) { 220 221 q := url.Values{} 222 223 if searchCriteria != nil && *searchCriteria != "" { 224 q.Set("search", string(*searchCriteria)) 225 } 226 227 if filterCriteria != nil && len(*filterCriteria) > 0 { 228 for filter, criteria := range *filterCriteria { 229 for _, val := range criteria { 230 q.Add(filter, val) 231 } 232 } 233 } 234 235 if q.Encode() == "" { 236 return a.FetchCheckBundles() 237 } 238 239 reqURL := url.URL{ 240 Path: config.CheckBundlePrefix, 241 RawQuery: q.Encode(), 242 } 243 244 resp, err := a.Get(reqURL.String()) 245 if err != nil { 246 return nil, fmt.Errorf("[ERROR] API call error %+v", err) 247 } 248 249 var results []CheckBundle 250 if err := json.Unmarshal(resp, &results); err != nil { 251 return nil, err 252 } 253 254 return &results, nil 255} 256