Skip to content
This repository has been archived by the owner on May 5, 2022. It is now read-only.

Add support for Service Event Rules #1

Merged
merged 2 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,14 @@ type ListRulesetRulesResponse struct {

// RuleActions represents a rule action
type RuleActions struct {
Suppress *RuleActionSuppress `json:"suppress,omitempty"`
Annotate *RuleActionParameter `json:"annotate,omitempty"`
Severity *RuleActionParameter `json:"severity,omitempty"`
Priority *RuleActionParameter `json:"priority,omitempty"`
Route *RuleActionParameter `json:"route"`
EventAction *RuleActionParameter `json:"event_action,omitempty"`
Extractions []*RuleActionExtraction `json:"extractions,omitempty"`
Priority *RuleActionParameter `json:"priority,omitempty"`
Severity *RuleActionParameter `json:"severity,omitempty"`
Suppress *RuleActionSuppress `json:"suppress,omitempty"`
Suspend *RuleActionSuspend `json:"suspend,omitempty"`
Route *RuleActionParameter `json:"route"`
}

// RuleActionParameter represents a generic parameter object on a rule action
Expand All @@ -126,6 +127,11 @@ type RuleActionSuppress struct {
ThresholdTimeAmount int `json:"threshold_time_amount,omitempty"`
}

// RuleActionSuspend represents a rule suspend action object
type RuleActionSuspend struct {
Value bool `json:"value,omitempty"`
}

// RuleActionExtraction represents a rule extraction action object
type RuleActionExtraction struct {
Target string `json:"target,omitempty"`
Expand Down
109 changes: 109 additions & 0 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,37 @@ type IncidentUrgencyRule struct {
OutsideSupportHours *IncidentUrgencyType `json:"outside_support_hours,omitempty"`
}

// ListServiceRulesResponse represents a list of rules in a service
type ListServiceRulesResponse struct {
Offset uint `json:"offset,omitempty"`
Limit uint `json:"limit,omitempty"`
More bool `json:"more,omitempty"`
Total uint `json:"total,omitempty"`
Rules []*ServiceRule `json:"rules,omitempty"`
}

// ServiceRule represents a Service rule
type ServiceRule struct {
ID string `json:"id,omitempty"`
Self string `json:"self,omitempty"`
Disabled bool `json:"disabled,omitempty"`
Conditions *RuleConditions `json:"conditions,omitempty"`
TimeFrame *RuleTimeFrame `json:"time_frame,omitempty"`
Position *int `json:"position,omitempty"`
Actions *ServiceRuleActions `json:"actions,omitempty"`
}

// ServiceRuleActions represents a rule action
type ServiceRuleActions struct {
Annotate *RuleActionParameter `json:"annotate,omitempty"`
EventAction *RuleActionParameter `json:"event_action,omitempty"`
Extractions []*RuleActionExtraction `json:"extractions,omitempty"`
Priority *RuleActionParameter `json:"priority,omitempty"`
Severity *RuleActionParameter `json:"severity,omitempty"`
Suppress *RuleActionSuppress `json:"suppress,omitempty"`
Suspend *RuleActionSuspend `json:"suspend,omitempty"`
}

// Service represents something you monitor (like a web service, email service, or database service).
type Service struct {
APIObject
Expand Down Expand Up @@ -220,6 +251,84 @@ func (c *Client) DeleteIntegration(serviceID string, integrationID string) error
return err
}

// ListServicetRules gets all rules for a service.
func (c *Client) ListServicetRules(serviceID string) (*ListServiceRulesResponse, error) {
rulesResponse := new(ListServiceRulesResponse)
rules := make([]*ServiceRule, 0)

// Create a handler closure capable of parsing data from the Service rules endpoint
// and appending resultant Service rules to the return slice.
responseHandler := func(response *http.Response) (APIListObject, error) {
var result ListServiceRulesResponse

if err := c.decodeJSON(response, &result); err != nil {
return APIListObject{}, err
}

rules = append(rules, result.Rules...)

// Return stats on the current page. Caller can use this information to
// adjust for requesting additional pages.
return APIListObject{
More: result.More,
Offset: result.Offset,
Limit: result.Limit,
}, nil
}

// Make call to get all pages associated with the base endpoint.
if err := c.pagedGet(context.TODO(), "/services/"+serviceID+"/rules", responseHandler); err != nil {
return nil, err
}
rulesResponse.Rules = rules

return rulesResponse, nil
}

// GetServiceRule gets a service rule.
func (c *Client) GetServiceRule(serviceID, ruleID string) (*ServiceRule, *http.Response, error) {
resp, err := c.get(context.TODO(), "/services/"+serviceID+"/rules/"+ruleID)
return getServiceRuleFromResponse(c, resp, err)
}

// DeleteServiceRule deletes a service rule.
func (c *Client) DeleteServiceRule(serviceID, ruleID string) error {
_, err := c.delete(context.TODO(), "/services/"+serviceID+"/rules/"+ruleID)
return err
}

// CreateServiceRule creates a service rule.
func (c *Client) CreateServiceRule(serviceID string, rule *ServiceRule) (*ServiceRule, *http.Response, error) {
data := make(map[string]*ServiceRule)
data["rule"] = rule
resp, err := c.post(context.TODO(), "/services/"+serviceID+"/rules/", data, nil)
return getServiceRuleFromResponse(c, resp, err)
}

// UpdateServiceRule updates a service rule.
func (c *Client) UpdateServiceRule(serviceID, ruleID string, rule *ServiceRule) (*ServiceRule, *http.Response, error) {
data := make(map[string]*ServiceRule)
data["rule"] = rule
resp, err := c.put(context.TODO(), "/services/"+serviceID+"/rules/"+ruleID, data, nil)
return getServiceRuleFromResponse(c, resp, err)
}

func getServiceRuleFromResponse(c *Client, resp *http.Response, err error) (*ServiceRule, *http.Response, error) {
if err != nil {
return nil, nil, err
}
var target map[string]ServiceRule
if dErr := c.decodeJSON(resp, &target); dErr != nil {
return nil, nil, fmt.Errorf("Could not decode JSON response: %v", dErr)
}
rootNode := "rule"
t, nodeOK := target[rootNode]
if !nodeOK {
return nil, nil, fmt.Errorf("JSON response does not have %s field", rootNode)
}
return &t, resp, nil
}

func getServiceFromResponse(c *Client, resp *http.Response, err error) (*Service, error) {
if err != nil {
return nil, err
Expand Down
126 changes: 126 additions & 0 deletions service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,129 @@ func TestService_DeleteIntegration(t *testing.T) {
t.Fatal(err)
}
}

// List Service Rules
func TestService_ListRules(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services/1/rules", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.Write([]byte(`{"rules": [{"id": "1"}]}`))
})

var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}

serviceID := "1"
res, err := client.ListServicetRules(serviceID)
if err != nil {
t.Fatal(err)
}

want := &ListServiceRulesResponse{
Rules: []*ServiceRule{
{
ID: "1",
},
},
}
testEqual(t, want, res)
}

// Create Service Rule
func TestService_CreateServiceRule(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services/1/rules/", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
w.Write([]byte(`{"rule": {"id": "1"}}`))
})

var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}

serviceID := "1"
rule := &ServiceRule{}

res, _, err := client.CreateServiceRule(serviceID, rule)
if err != nil {
t.Fatal(err)
}

want := &ServiceRule{
ID: "1",
}
testEqual(t, want, res)
}

// Get Service Rule
func TestService_GetServiceRule(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services/1/rules/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.Write([]byte(`{"rule": {"id": "1"}}`))
})

var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}

serviceID := "1"
ruleID := "1"
res, _, err := client.GetServiceRule(serviceID, ruleID)
if err != nil {
t.Fatal(err)
}

want := &ServiceRule{
ID: "1",
}
testEqual(t, want, res)
}

// Update Service Rule
func TestService_UpdateServiceRule(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services/1/rules/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.Write([]byte(`{"rule": {"id": "1"}}`))
})

var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}

serviceID := "1"
ruleID := "1"
rule := &ServiceRule{}

res, _, err := client.UpdateServiceRule(serviceID, ruleID, rule)
if err != nil {
t.Fatal(err)
}

want := &ServiceRule{
ID: "1",
}
testEqual(t, want, res)
}

// Delete Service Rule
func TestService_DeleteServiceRule(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/services/1/rules/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})

var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}
serviceID := "1"
ruleID := "1"

err := client.DeleteServiceRule(serviceID, ruleID)

if err != nil {
t.Fatal(err)
}
}