From 8a0d6b21743c43ff636dcc3b790bb5eaee01b912 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Mon, 15 Jun 2020 09:55:43 -0700 Subject: [PATCH 1/2] adding business_service and service_dependency --- ruleset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruleset.go b/ruleset.go index 0fb9dd75..e0c188f7 100644 --- a/ruleset.go +++ b/ruleset.go @@ -173,7 +173,7 @@ func (c *Client) CreateRuleset(r *Ruleset) (*Ruleset, *http.Response, error) { return getRulesetFromResponse(c, resp, err) } -// DeleteRuleset deletes a user. +// DeleteRuleset deletes a ruleset. func (c *Client) DeleteRuleset(id string) error { _, err := c.delete("/rulesets/" + id) return err From 23cbde20db98774c7ce93faa3af3f6fd8744b61e Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Mon, 15 Jun 2020 10:01:15 -0700 Subject: [PATCH 2/2] adding code for business_service and service_dependency endpoints --- business_service.go | 127 ++++++++++++++++++++++++++++ business_service_test.go | 135 +++++++++++++++++++++++++++++ service_dependency.go | 68 +++++++++++++++ service_dependency_test.go | 168 +++++++++++++++++++++++++++++++++++++ 4 files changed, 498 insertions(+) create mode 100644 business_service.go create mode 100644 business_service_test.go create mode 100644 service_dependency.go create mode 100644 service_dependency_test.go diff --git a/business_service.go b/business_service.go new file mode 100644 index 00000000..bdf8f651 --- /dev/null +++ b/business_service.go @@ -0,0 +1,127 @@ +package pagerduty + +import ( + "fmt" + "net/http" + + "github.com/google/go-querystring/query" +) + +// BusinessService represents a business service. +type BusinessService struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Summary string `json:"summary,omitempty"` + Self string `json:"self,omitempty"` + PointOfContact string `json:"point_of_contact,omitempty"` + HTMLUrl string `json:"html_url,omitempty"` + Description string `json:"description,omitempty"` + Team *BusinessServiceTeam `json:"team,omitempty"` +} + +// BusinessServiceTeam represents a team object in a business service +type BusinessServiceTeam struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Self string `json:"self,omitempty"` +} + +// BusinessServicePayload represents payload with a business service object +type BusinessServicePayload struct { + BusinessService *BusinessService `json:"business_service,omitempty"` +} + +// ListBusinessServicesResponse represents a list response of business services. +type ListBusinessServicesResponse struct { + Total uint `json:"total,omitempty"` + BusinessServices []*BusinessService `json:"business_services,omitempty"` + Offset uint `json:"offset,omitempty"` + More bool `json:"more,omitempty"` + Limit uint `json:"limit,omitempty"` +} + +// ListBusinessServiceOptions is the data structure used when calling the ListBusinessServices API endpoint. +type ListBusinessServiceOptions struct { + APIListObject +} + +// ListBusinessServices lists existing business services. +func (c *Client) ListBusinessServices(o ListBusinessServiceOptions) (*ListBusinessServicesResponse, error) { + queryParms, err := query.Values(o) + if err != nil { + return nil, err + } + businessServiceResponse := new(ListBusinessServicesResponse) + businessServices := make([]*BusinessService, 0) + + // Create a handler closure capable of parsing data from the business_services endpoint + // and appending resultant business_services to the return slice. + responseHandler := func(response *http.Response) (APIListObject, error) { + var result ListBusinessServicesResponse + if err := c.decodeJSON(response, &result); err != nil { + return APIListObject{}, err + } + + businessServices = append(businessServices, result.BusinessServices...) + + // 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("/business_services"+queryParms.Encode(), responseHandler); err != nil { + return nil, err + } + businessServiceResponse.BusinessServices = businessServices + + return businessServiceResponse, nil +} + +// CreateBusinessService creates a new business service. +func (c *Client) CreateBusinessService(b *BusinessService) (*BusinessService, *http.Response, error) { + data := make(map[string]*BusinessService) + data["business_service"] = b + resp, err := c.post("/business_services", data, nil) + return getBusinessServiceFromResponse(c, resp, err) +} + +// GetBusinessService gets details about a business service. +func (c *Client) GetBusinessService(ID string) (*BusinessService, *http.Response, error) { + resp, err := c.get("/business_services/" + ID) + return getBusinessServiceFromResponse(c, resp, err) +} + +// DeleteBusinessService deletes a business_service. +func (c *Client) DeleteBusinessService(ID string) error { + _, err := c.delete("/business_services/" + ID) + return err +} + +// UpdateBusinessService updates a business_service. +func (c *Client) UpdateBusinessService(b *BusinessService) (*BusinessService, *http.Response, error) { + v := make(map[string]*BusinessService) + v["business_service"] = b + resp, err := c.put("/business_services/"+b.ID, v, nil) + return getBusinessServiceFromResponse(c, resp, err) +} + +func getBusinessServiceFromResponse(c *Client, resp *http.Response, err error) (*BusinessService, *http.Response, error) { + if err != nil { + return nil, nil, err + } + var target map[string]BusinessService + if dErr := c.decodeJSON(resp, &target); dErr != nil { + return nil, nil, fmt.Errorf("Could not decode JSON response: %v", dErr) + } + t, nodeOK := target["business_service"] + if !nodeOK { + return nil, nil, fmt.Errorf("JSON response does not have business_service field") + } + return &t, resp, nil +} diff --git a/business_service_test.go b/business_service_test.go new file mode 100644 index 00000000..c8c52272 --- /dev/null +++ b/business_service_test.go @@ -0,0 +1,135 @@ +package pagerduty + +import ( + "net/http" + "testing" +) + +// List BusinessServices +func TestBusinessService_List(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/business_services/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.Write([]byte(`{"business_services": [{"id": "1"}]}`)) + }) + + var listObj = APIListObject{Limit: 0, Offset: 0, More: false, Total: 0} + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + var opts = ListBusinessServiceOptions{ + APIListObject: listObj, + } + res, err := client.ListBusinessServices(opts) + if err != nil { + t.Fatal(err) + } + want := &ListBusinessServicesResponse{ + BusinessServices: []*BusinessService{ + { + ID: "1", + }, + }, + } + + testEqual(t, want, res) +} + +// Create BusinessService +func TestBusinessService_Create(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/business_services", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + w.Write([]byte(`{"business_service": {"id": "1", "name": "foo"}}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + input := &BusinessService{ + Name: "foo", + } + res, _, err := client.CreateBusinessService(input) + + want := &BusinessService{ + ID: "1", + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Get BusinessService +func TestBusinessService_Get(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/business_services/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.Write([]byte(`{"business_service": {"id": "1", "name":"foo"}}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + ruleSetID := "1" + + res, _, err := client.GetBusinessService(ruleSetID) + + want := &BusinessService{ + ID: "1", + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Update BusinessService +func TestBusinessService_Update(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/business_services/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + w.Write([]byte(`{"business_service": {"id": "1", "name":"foo"}}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + input := &BusinessService{ + ID: "1", + Name: "foo", + } + res, _, err := client.UpdateBusinessService(input) + + want := &BusinessService{ + ID: "1", + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Delete BusinessService +func TestBusinessService_Delete(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/business_services/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + ID := "1" + err := client.DeleteBusinessService(ID) + + if err != nil { + t.Fatal(err) + } +} diff --git a/service_dependency.go b/service_dependency.go new file mode 100644 index 00000000..7cf0fa2a --- /dev/null +++ b/service_dependency.go @@ -0,0 +1,68 @@ +package pagerduty + +import ( + "net/http" +) + +// ServiceDependency represents a relationship between a business and technical service +type ServiceDependency struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + SupportingService *ServiceObj `json:"supporting_service,omitempty"` + DependentService *ServiceObj `json:"dependent_service,omitempty"` +} + +// ServiceObj represents a service object in service relationship +type ServiceObj struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` +} + +// ListServiceDependencies represents a list of dependencies for a service +type ListServiceDependencies struct { + Relationships []*ServiceDependency `json:"relationships,omitempty"` +} + +// ListBusinessServiceDependencies lists dependencies of a business service. +func (c *Client) ListBusinessServiceDependencies(businessServiceID string) (*ListServiceDependencies, *http.Response, error) { + resp, err := c.get("/service_dependencies/business_services/" + businessServiceID) + if err != nil { + return nil, nil, err + } + var result ListServiceDependencies + return &result, resp, c.decodeJSON(resp, &result) +} + +// ListTechnicalServiceDependencies lists dependencies of a technical service. +func (c *Client) ListTechnicalServiceDependencies(serviceID string) (*ListServiceDependencies, *http.Response, error) { + resp, err := c.get("/service_dependencies/technical_services/" + serviceID) + if err != nil { + return nil, nil, err + } + var result ListServiceDependencies + return &result, resp, c.decodeJSON(resp, &result) +} + +// AssociateServiceDependencies Create new dependencies between two services. +func (c *Client) AssociateServiceDependencies(dependencies *ListServiceDependencies) (*ListServiceDependencies, *http.Response, error) { + data := make(map[string]*ListServiceDependencies) + data["relationships"] = dependencies + resp, err := c.post("/service_dependencies/associate", data, nil) + if err != nil { + return nil, nil, err + } + var result ListServiceDependencies + return &result, resp, c.decodeJSON(resp, &result) +} + +// DisassociateServiceDependencies Disassociate dependencies between two services. +func (c *Client) DisassociateServiceDependencies(dependencies *ListServiceDependencies) (*ListServiceDependencies, *http.Response, error) { + data := make(map[string]*ListServiceDependencies) + data["relationships"] = dependencies + resp, err := c.post("/service_dependencies/disassociate", data, nil) + if err != nil { + return nil, nil, err + } + var result ListServiceDependencies + return &result, resp, c.decodeJSON(resp, &result) +} diff --git a/service_dependency_test.go b/service_dependency_test.go new file mode 100644 index 00000000..7283f849 --- /dev/null +++ b/service_dependency_test.go @@ -0,0 +1,168 @@ +package pagerduty + +import ( + "net/http" + "testing" +) + +// List BusinessService Dependencies +func TestBusinessServiceDependency_List(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/service_dependencies/business_services/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.Write([]byte(`{"relationships": [{"id": "1","dependent_service":{"id":"1"},"supporting_service":{"id":"1"},"type":"service_dependency"}]}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + bServeID := "1" + res, _, err := client.ListBusinessServiceDependencies(bServeID) + if err != nil { + t.Fatal(err) + } + want := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + + testEqual(t, want, res) +} + +// List TechnicalService Dependencies +func TestTechnicalServiceDependency_List(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/service_dependencies/technical_services/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.Write([]byte(`{"relationships": [{"id": "1","dependent_service":{"id":"1"},"supporting_service":{"id":"1"},"type":"service_dependency"}]}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + bServeID := "1" + res, _, err := client.ListTechnicalServiceDependencies(bServeID) + if err != nil { + t.Fatal(err) + } + want := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + + testEqual(t, want, res) +} + +// AssociateServiceDependencies +func TestServiceDependency_Associate(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/service_dependencies/associate", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + w.Write([]byte(`{"relationships": [{"id": "1","dependent_service":{"id":"1"},"supporting_service":{"id":"1"},"type":"service_dependency"}]}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + input := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + res, _, err := client.AssociateServiceDependencies(input) + + if err != nil { + t.Fatal(err) + } + want := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + testEqual(t, want, res) +} + +// DisassociateServiceDependencies +func TestServiceDependency_Disassociate(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/service_dependencies/disassociate", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + w.Write([]byte(`{"relationships": [{"id": "1","dependent_service":{"id":"1"},"supporting_service":{"id":"1"},"type":"service_dependency"}]}`)) + }) + + var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient} + input := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + res, _, err := client.DisassociateServiceDependencies(input) + + if err != nil { + t.Fatal(err) + } + want := &ListServiceDependencies{ + Relationships: []*ServiceDependency{ + { + ID: "1", + Type: "service_dependency", + DependentService: &ServiceObj{ + ID: "1", + }, + SupportingService: &ServiceObj{ + ID: "1", + }, + }, + }, + } + testEqual(t, want, res) +}