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// Maintenance window API support - Fetch, Create, Update, Delete, and Search
6// See: https://login.circonus.com/resources/api/calls/maintenance
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// Maintenance defines a maintenance window. See https://login.circonus.com/resources/api/calls/maintenance for more information.
20type Maintenance struct {
21	CID        string      `json:"_cid,omitempty"`       // string
22	Item       string      `json:"item,omitempty"`       // string
23	Notes      string      `json:"notes,omitempty"`      // string
24	Severities interface{} `json:"severities,omitempty"` // []string NOTE can be set with CSV string or []string
25	Start      uint        `json:"start,omitempty"`      // uint
26	Stop       uint        `json:"stop,omitempty"`       // uint
27	Tags       []string    `json:"tags,omitempty"`       // [] len >= 0
28	Type       string      `json:"type,omitempty"`       // string
29}
30
31// NewMaintenanceWindow returns a new Maintenance window (with defaults, if applicable)
32func NewMaintenanceWindow() *Maintenance {
33	return &Maintenance{}
34}
35
36// FetchMaintenanceWindow retrieves maintenance [window] with passed cid.
37func (a *API) FetchMaintenanceWindow(cid CIDType) (*Maintenance, error) {
38	if cid == nil || *cid == "" {
39		return nil, fmt.Errorf("Invalid maintenance window CID [none]")
40	}
41
42	maintenanceCID := string(*cid)
43
44	matched, err := regexp.MatchString(config.MaintenanceCIDRegex, maintenanceCID)
45	if err != nil {
46		return nil, err
47	}
48	if !matched {
49		return nil, fmt.Errorf("Invalid maintenance window CID [%s]", maintenanceCID)
50	}
51
52	result, err := a.Get(maintenanceCID)
53	if err != nil {
54		return nil, err
55	}
56
57	if a.Debug {
58		a.Log.Printf("[DEBUG] fetch maintenance window, received JSON: %s", string(result))
59	}
60
61	window := &Maintenance{}
62	if err := json.Unmarshal(result, window); err != nil {
63		return nil, err
64	}
65
66	return window, nil
67}
68
69// FetchMaintenanceWindows retrieves all maintenance [windows] available to API Token.
70func (a *API) FetchMaintenanceWindows() (*[]Maintenance, error) {
71	result, err := a.Get(config.MaintenancePrefix)
72	if err != nil {
73		return nil, err
74	}
75
76	var windows []Maintenance
77	if err := json.Unmarshal(result, &windows); err != nil {
78		return nil, err
79	}
80
81	return &windows, nil
82}
83
84// UpdateMaintenanceWindow updates passed maintenance [window].
85func (a *API) UpdateMaintenanceWindow(cfg *Maintenance) (*Maintenance, error) {
86	if cfg == nil {
87		return nil, fmt.Errorf("Invalid maintenance window config [nil]")
88	}
89
90	maintenanceCID := string(cfg.CID)
91
92	matched, err := regexp.MatchString(config.MaintenanceCIDRegex, maintenanceCID)
93	if err != nil {
94		return nil, err
95	}
96	if !matched {
97		return nil, fmt.Errorf("Invalid maintenance window CID [%s]", maintenanceCID)
98	}
99
100	jsonCfg, err := json.Marshal(cfg)
101	if err != nil {
102		return nil, err
103	}
104
105	if a.Debug {
106		a.Log.Printf("[DEBUG] update maintenance window, sending JSON: %s", string(jsonCfg))
107	}
108
109	result, err := a.Put(maintenanceCID, jsonCfg)
110	if err != nil {
111		return nil, err
112	}
113
114	window := &Maintenance{}
115	if err := json.Unmarshal(result, window); err != nil {
116		return nil, err
117	}
118
119	return window, nil
120}
121
122// CreateMaintenanceWindow creates a new maintenance [window].
123func (a *API) CreateMaintenanceWindow(cfg *Maintenance) (*Maintenance, error) {
124	if cfg == nil {
125		return nil, fmt.Errorf("Invalid maintenance window config [nil]")
126	}
127
128	jsonCfg, err := json.Marshal(cfg)
129	if err != nil {
130		return nil, err
131	}
132
133	if a.Debug {
134		a.Log.Printf("[DEBUG] create maintenance window, sending JSON: %s", string(jsonCfg))
135	}
136
137	result, err := a.Post(config.MaintenancePrefix, jsonCfg)
138	if err != nil {
139		return nil, err
140	}
141
142	window := &Maintenance{}
143	if err := json.Unmarshal(result, window); err != nil {
144		return nil, err
145	}
146
147	return window, nil
148}
149
150// DeleteMaintenanceWindow deletes passed maintenance [window].
151func (a *API) DeleteMaintenanceWindow(cfg *Maintenance) (bool, error) {
152	if cfg == nil {
153		return false, fmt.Errorf("Invalid maintenance window config [nil]")
154	}
155	return a.DeleteMaintenanceWindowByCID(CIDType(&cfg.CID))
156}
157
158// DeleteMaintenanceWindowByCID deletes maintenance [window] with passed cid.
159func (a *API) DeleteMaintenanceWindowByCID(cid CIDType) (bool, error) {
160	if cid == nil || *cid == "" {
161		return false, fmt.Errorf("Invalid maintenance window CID [none]")
162	}
163
164	maintenanceCID := string(*cid)
165
166	matched, err := regexp.MatchString(config.MaintenanceCIDRegex, maintenanceCID)
167	if err != nil {
168		return false, err
169	}
170	if !matched {
171		return false, fmt.Errorf("Invalid maintenance window CID [%s]", maintenanceCID)
172	}
173
174	_, err = a.Delete(maintenanceCID)
175	if err != nil {
176		return false, err
177	}
178
179	return true, nil
180}
181
182// SearchMaintenanceWindows returns maintenance [windows] matching
183// the specified search query and/or filter. If nil is passed for
184// both parameters all maintenance [windows] will be returned.
185func (a *API) SearchMaintenanceWindows(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Maintenance, error) {
186	q := url.Values{}
187
188	if searchCriteria != nil && *searchCriteria != "" {
189		q.Set("search", string(*searchCriteria))
190	}
191
192	if filterCriteria != nil && len(*filterCriteria) > 0 {
193		for filter, criteria := range *filterCriteria {
194			for _, val := range criteria {
195				q.Add(filter, val)
196			}
197		}
198	}
199
200	if q.Encode() == "" {
201		return a.FetchMaintenanceWindows()
202	}
203
204	reqURL := url.URL{
205		Path:     config.MaintenancePrefix,
206		RawQuery: q.Encode(),
207	}
208
209	result, err := a.Get(reqURL.String())
210	if err != nil {
211		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
212	}
213
214	var windows []Maintenance
215	if err := json.Unmarshal(result, &windows); err != nil {
216		return nil, err
217	}
218
219	return &windows, nil
220}
221