From e92bc7b63cd52834adb835651501f700abe5f289 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 3 Jun 2020 18:16:47 -0700 Subject: [PATCH 1/2] add support for technical service dependencies --- go.mod | 2 +- go.sum | 2 + ...mport_pagerduty_service_dependency_test.go | 4 +- .../resource_pagerduty_service_dependency.go | 14 +- ...ource_pagerduty_service_dependency_test.go | 165 ++++++++++++++++-- .../pagerduty/business_service.go | 24 ++- .../pagerduty/service_dependency.go | 28 ++- vendor/modules.txt | 2 +- .../docs/r/service_dependency.html.markdown | 6 +- 9 files changed, 212 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 214abafc1..2aa562460 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-pagerduty require ( github.com/google/go-querystring v1.0.0 // indirect github.com/hashicorp/terraform-plugin-sdk v1.7.0 - github.com/heimweh/go-pagerduty v0.0.0-20200528011640-24a6d8472a24 + github.com/heimweh/go-pagerduty v0.0.0-20200603015639-6677e9a50383 ) go 1.13 diff --git a/go.sum b/go.sum index babf2ee12..28c358b4b 100644 --- a/go.sum +++ b/go.sum @@ -196,6 +196,8 @@ github.com/heimweh/go-pagerduty v0.0.0-20200429000711-fdd3a48907e7 h1:8groiuI/ki github.com/heimweh/go-pagerduty v0.0.0-20200429000711-fdd3a48907e7/go.mod h1:6+bccpjQ/PM8uQY9m8avM4MJea+3vo3ta9r8kGQ4XFY= github.com/heimweh/go-pagerduty v0.0.0-20200528011640-24a6d8472a24 h1:ga84s0DaOnrYN7IL7jMug6ins5QpiMuNpXFxCKqFAvg= github.com/heimweh/go-pagerduty v0.0.0-20200528011640-24a6d8472a24/go.mod h1:6+bccpjQ/PM8uQY9m8avM4MJea+3vo3ta9r8kGQ4XFY= +github.com/heimweh/go-pagerduty v0.0.0-20200603015639-6677e9a50383 h1:IMMksFroOt5lul7trOUQZjP4nlCIE5XiRrJqCxZ07Jo= +github.com/heimweh/go-pagerduty v0.0.0-20200603015639-6677e9a50383/go.mod h1:6+bccpjQ/PM8uQY9m8avM4MJea+3vo3ta9r8kGQ4XFY= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= diff --git a/pagerduty/import_pagerduty_service_dependency_test.go b/pagerduty/import_pagerduty_service_dependency_test.go index 7335b7858..194c68aca 100644 --- a/pagerduty/import_pagerduty_service_dependency_test.go +++ b/pagerduty/import_pagerduty_service_dependency_test.go @@ -19,10 +19,10 @@ func TestAccPagerDutyServiceDependency_import(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckPagerDutyServiceDependencyDestroy, + CheckDestroy: testAccCheckPagerDutyBusinessServiceDependencyDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckPagerDutyServiceDependencyConfig(service, businessService, username, email, escalationPolicy), + Config: testAccCheckPagerDutyBusinessServiceDependencyConfig(service, businessService, username, email, escalationPolicy), }, { diff --git a/pagerduty/resource_pagerduty_service_dependency.go b/pagerduty/resource_pagerduty_service_dependency.go index af52e71cf..ab21df1ea 100644 --- a/pagerduty/resource_pagerduty_service_dependency.go +++ b/pagerduty/resource_pagerduty_service_dependency.go @@ -144,7 +144,7 @@ func resourcePagerDutyServiceDependencyDisassociate(d *schema.ResourceData, meta log.Printf("[INFO] Disassociating PagerDuty dependency %s", dependency.DependentService.ID) // listServiceRelationships by calling get dependencies using the serviceDependency.DependentService.ID - depResp, _, err := client.ServiceDependencies.GetBusinessServiceDependencies(dependency.DependentService.ID) + depResp, _, err := client.ServiceDependencies.GetServiceDependenciesForType(dependency.DependentService.ID, dependency.DependentService.Type) if err != nil { return err } @@ -188,7 +188,7 @@ func resourcePagerDutyServiceDependencyRead(d *schema.ResourceData, meta interfa serviceDependency, err := buildServiceDependencyStruct(d) log.Printf("[INFO] Reading PagerDuty dependency %s", serviceDependency.ID) - if err = findDependencySetState(d.Id(), serviceDependency.DependentService.ID, d, meta); err != nil { + if err = findDependencySetState(d.Id(), serviceDependency.DependentService.ID, serviceDependency.DependentService.Type, d, meta); err != nil { return err } @@ -230,13 +230,13 @@ func convertType(s string) string { return s } -func findDependencySetState(depID, busServiceID string, d *schema.ResourceData, meta interface{}) error { +func findDependencySetState(depID, serviceID, serviceType string, d *schema.ResourceData, meta interface{}) error { client := meta.(*pagerduty.Client) // Pausing to let the PD API sync. time.Sleep(1 * time.Second) retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { - if dependencies, _, err := client.ServiceDependencies.GetBusinessServiceDependencies(busServiceID); err != nil { + if dependencies, _, err := client.ServiceDependencies.GetServiceDependenciesForType(serviceID, serviceType); err != nil { if isErrCode(err, 404) || isErrCode(err, 500) || isErrCode(err, 429) { return resource.RetryableError(err) } @@ -266,11 +266,11 @@ func resourcePagerDutyServiceDependencyImport(d *schema.ResourceData, meta inter ids := strings.Split(d.Id(), ".") if len(ids) != 2 { - return []*schema.ResourceData{}, fmt.Errorf("Error importing pagerduty_service_dependency. Expecting an importation ID formed as '.'") + return []*schema.ResourceData{}, fmt.Errorf("Error importing pagerduty_service_dependency. Expecting an importation ID formed as '..'") } - sid, id := ids[0], ids[1] + sid, st, id := ids[0], ids[1], ids[2] - if err := findDependencySetState(id, sid, d, meta); err != nil { + if err := findDependencySetState(id, sid, st, d, meta); err != nil { return []*schema.ResourceData{}, err } diff --git a/pagerduty/resource_pagerduty_service_dependency_test.go b/pagerduty/resource_pagerduty_service_dependency_test.go index f18c91a22..a739b40c0 100644 --- a/pagerduty/resource_pagerduty_service_dependency_test.go +++ b/pagerduty/resource_pagerduty_service_dependency_test.go @@ -10,7 +10,8 @@ import ( "github.com/heimweh/go-pagerduty/pagerduty" ) -func TestAccPagerDutyServiceDependency_Basic(t *testing.T) { +// Testing Business Service Dependencies +func TestAccPagerDutyBusinessServiceDependency_Basic(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) businessService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -20,12 +21,12 @@ func TestAccPagerDutyServiceDependency_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckPagerDutyServiceDependencyDestroy, + CheckDestroy: testAccCheckPagerDutyBusinessServiceDependencyDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckPagerDutyServiceDependencyConfig(service, businessService, username, email, escalationPolicy), + Config: testAccCheckPagerDutyBusinessServiceDependencyConfig(service, businessService, username, email, escalationPolicy), Check: resource.ComposeTestCheckFunc( - testAccCheckPagerDutyServiceDependencyExists("pagerduty_service_dependency.foo"), + testAccCheckPagerDutyBusinessServiceDependencyExists("pagerduty_service_dependency.foo"), resource.TestCheckResourceAttr( "pagerduty_service_dependency.foo", "dependency.#", "1"), resource.TestCheckResourceAttr( @@ -37,7 +38,7 @@ func TestAccPagerDutyServiceDependency_Basic(t *testing.T) { }, }) } -func testAccCheckPagerDutyServiceDependencyExists(n string) resource.TestCheckFunc { +func testAccCheckPagerDutyBusinessServiceDependencyExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -47,12 +48,11 @@ func testAccCheckPagerDutyServiceDependencyExists(n string) resource.TestCheckFu if rs.Primary.ID == "" { return fmt.Errorf("No Service Relationship ID is set") } - businessService, _ := s.RootModule().Resources["pagerduty_business_service.foo"] client := testAccProvider.Meta().(*pagerduty.Client) - depResp, _, err := client.ServiceDependencies.GetBusinessServiceDependencies(businessService.Primary.ID) + depResp, _, err := client.ServiceDependencies.GetServiceDependenciesForType(businessService.Primary.ID, "business_service") if err != nil { return fmt.Errorf("Business Service not found: %v", err) } @@ -73,7 +73,7 @@ func testAccCheckPagerDutyServiceDependencyExists(n string) resource.TestCheckFu } } -func testAccCheckPagerDutyServiceDependencyDestroy(s *terraform.State) error { +func testAccCheckPagerDutyBusinessServiceDependencyDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*pagerduty.Client) for _, r := range s.RootModule().Resources { if r.Type != "pagerduty_service_dependency" { @@ -82,7 +82,7 @@ func testAccCheckPagerDutyServiceDependencyDestroy(s *terraform.State) error { businessService, _ := s.RootModule().Resources["pagerduty_business_service.foo"] // get business service - dependencies, _, err := client.ServiceDependencies.GetBusinessServiceDependencies(businessService.Primary.ID) + dependencies, _, err := client.ServiceDependencies.GetServiceDependenciesForType(businessService.Primary.ID, "business_service") if err != nil { // if the business service doesn't exist, that's okay return nil @@ -90,14 +90,14 @@ func testAccCheckPagerDutyServiceDependencyDestroy(s *terraform.State) error { // get business service dependencies for _, rel := range dependencies.Relationships { if rel.ID == r.Primary.ID { - return fmt.Errorf("Business service relationship still exists") + return fmt.Errorf("supporting service relationship still exists") } } } return nil } -func testAccCheckPagerDutyServiceDependencyConfig(service, businessService, username, email, escalationPolicy string) string { +func testAccCheckPagerDutyBusinessServiceDependencyConfig(service, businessService, username, email, escalationPolicy string) string { return fmt.Sprintf(` resource "pagerduty_business_service" "foo" { name = "%s" @@ -146,3 +146,146 @@ resource "pagerduty_service_dependency" "foo" { } `, businessService, username, email, escalationPolicy, service) } + +// Testing Technical Service Dependencies +func TestAccPagerDutyTechnicalServiceDependency_Basic(t *testing.T) { + dependentService := fmt.Sprintf("tf-%s", acctest.RandString(5)) + supportingService := fmt.Sprintf("tf-%s", acctest.RandString(5)) + username := fmt.Sprintf("tf-%s", acctest.RandString(5)) + email := fmt.Sprintf("%s@foo.com", username) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyTechnicalServiceDependencyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyTechnicalServiceDependencyConfig(dependentService, supportingService, username, email, escalationPolicy), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyTechnicalServiceDependencyExists("pagerduty_service_dependency.bar"), + resource.TestCheckResourceAttr( + "pagerduty_service_dependency.bar", "dependency.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_service_dependency.bar", "dependency.0.supporting_service.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_service_dependency.bar", "dependency.0.dependent_service.#", "1"), + ), + }, + }, + }) +} +func testAccCheckPagerDutyTechnicalServiceDependencyExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Service Relationship ID is set") + } + supportService, _ := s.RootModule().Resources["pagerduty_service.supportBar"] + + client := testAccProvider.Meta().(*pagerduty.Client) + + depResp, _, err := client.ServiceDependencies.GetServiceDependenciesForType(supportService.Primary.ID, "service") + if err != nil { + return fmt.Errorf("Technical Service not found: %v", err) + } + var foundRel *pagerduty.ServiceDependency + + // loop serviceRelationships until relationship.IDs match + for _, rel := range depResp.Relationships { + if rel.ID == rs.Primary.ID { + foundRel = rel + break + } + } + if foundRel == nil { + return fmt.Errorf("Service Dependency not found: %v", rs.Primary.ID) + } + + return nil + } +} + +func testAccCheckPagerDutyTechnicalServiceDependencyDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*pagerduty.Client) + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_service_dependency" { + continue + } + supportService, _ := s.RootModule().Resources["pagerduty_service.supportBar"] + + // get service dependencies + dependencies, _, err := client.ServiceDependencies.GetServiceDependenciesForType(supportService.Primary.ID, "service") + if err != nil { + // if the dependency doesn't exist, that's okay + return nil + } + // find desired dependency + for _, rel := range dependencies.Relationships { + if rel.ID == r.Primary.ID { + return fmt.Errorf("supporting service relationship still exists") + } + } + + } + return nil +} +func testAccCheckPagerDutyTechnicalServiceDependencyConfig(dependentService, supportingService, username, email, escalationPolicy string) string { + return fmt.Sprintf(` + + +resource "pagerduty_user" "bar" { + name = "%s" + email = "%s" + color = "green" + role = "user" + job_title = "foo" + description = "foo" +} + +resource "pagerduty_escalation_policy" "bar" { + name = "%s" + description = "bar-desc" + num_loops = 2 + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.bar.id + } + } +} +resource "pagerduty_service" "supportBar" { + name = "%s" + description = "supportBarDesc" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.bar.id + alert_creation = "create_incidents" +} +resource "pagerduty_service" "dependBar" { + name = "%s" + description = "dependBarDesc" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.bar.id + alert_creation = "create_incidents" +} +resource "pagerduty_service_dependency" "bar" { + dependency { + dependent_service { + id = pagerduty_service.dependBar.id + type = "service" + } + supporting_service { + id = pagerduty_service.supportBar.id + type = "service" + } + } +} +`, username, email, escalationPolicy, supportingService, dependentService) +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/business_service.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/business_service.go index a8006358f..4a3de14d9 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/business_service.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/business_service.go @@ -8,14 +8,22 @@ type BusinessServiceService service // 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"` + 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 diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/service_dependency.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/service_dependency.go index eebcecd91..5ef485ff5 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/service_dependency.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/service_dependency.go @@ -52,8 +52,19 @@ func (s *ServiceDependencyService) DisassociateServiceDependencies(dependencies return v, resp, nil } -// GetBusinessServiceDependencies gets all immediate dependencies of a business service. -func (s *ServiceDependencyService) GetBusinessServiceDependencies(businessServiceID string) (*ListServiceDependencies, *Response, error) { +// GetServiceDependenciesForType gets all immediate dependencies of a dependent service. +func (s *ServiceDependencyService) GetServiceDependenciesForType(serviceID, serviceType string) (*ListServiceDependencies, *Response, error) { + if serviceType == "business_service" || serviceType == "business_service_reference" { + return s.getBusinessServiceDependencies(serviceID) + } else if serviceType == "service" || serviceType == "technical_service_reference" { + return s.getTechnicalServiceDependencies(serviceID) + } + // return a not found error + return nil, nil, fmt.Errorf("dependent Service type of %s not found", serviceType) +} + +// getBusinessServiceDependencies gets all immediate dependencies of a business service. +func (s *ServiceDependencyService) getBusinessServiceDependencies(businessServiceID string) (*ListServiceDependencies, *Response, error) { u := fmt.Sprintf("/service_dependencies/business_services/%s", businessServiceID) v := new(ListServiceDependencies) @@ -64,3 +75,16 @@ func (s *ServiceDependencyService) GetBusinessServiceDependencies(businessServic return v, resp, nil } + +// getTechnicalServiceDependencies gets all immediate dependencies of a technical service. +func (s *ServiceDependencyService) getTechnicalServiceDependencies(serviceID string) (*ListServiceDependencies, *Response, error) { + u := fmt.Sprintf("/service_dependencies/technical_services/%s", serviceID) + v := new(ListServiceDependencies) + + resp, err := s.client.newRequestDo("GET", u, nil, nil, &v) + if err != nil { + return nil, nil, err + } + + return v, resp, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ab8992cc6..58cc2fafc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -182,7 +182,7 @@ github.com/hashicorp/terraform-svchost/auth github.com/hashicorp/terraform-svchost/disco # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/heimweh/go-pagerduty v0.0.0-20200528011640-24a6d8472a24 +# github.com/heimweh/go-pagerduty v0.0.0-20200603015639-6677e9a50383 github.com/heimweh/go-pagerduty/pagerduty # github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath diff --git a/website/docs/r/service_dependency.html.markdown b/website/docs/r/service_dependency.html.markdown index 20972bb39..05b0031b4 100644 --- a/website/docs/r/service_dependency.html.markdown +++ b/website/docs/r/service_dependency.html.markdown @@ -8,7 +8,7 @@ description: |- # pagerduty\_service\_dependency -A [service dependency](https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1service_dependencies~1associate/post) is a relationship between a business service and technical and business services that this service uses, or that are used by this service, and are critical for successful operation. +A [service dependency](https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1service_dependencies~1associate/post) is a relationship between two services that this service uses, or that are used by this service, and are critical for successful operation. ## Example Usage @@ -57,8 +57,8 @@ The following attributes are exported: ## Import -Service dependencies can be imported using the related business service id and the dependency id separated by a dot, e.g. +Service dependencies can be imported using the related supporting service id, supporting service type (`business_service` or `service`) and the dependency id separated by a dot, e.g. ``` -$ terraform import pagerduty_service_dependency.main P4B2Z7G.D5RTHKRNGU4PYE90PJ +$ terraform import pagerduty_service_dependency.main P4B2Z7G.business_service.D5RTHKRNGU4PYE90PJ ``` From e3b87265f5f262f5faead5b731865fed73659dd6 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 3 Jun 2020 18:46:15 -0700 Subject: [PATCH 2/2] adding note to service_dependency docs --- website/docs/r/service_dependency.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/service_dependency.html.markdown b/website/docs/r/service_dependency.html.markdown index 05b0031b4..1b5f02b13 100644 --- a/website/docs/r/service_dependency.html.markdown +++ b/website/docs/r/service_dependency.html.markdown @@ -55,6 +55,8 @@ The following attributes are exported: * `id` - The ID of the service dependency. +***NOTE: Due to the API supporting this resource, it does not support updating. To make changes to a `service_dependency` you'll need to destroy and then create a new one.*** + ## Import Service dependencies can be imported using the related supporting service id, supporting service type (`business_service` or `service`) and the dependency id separated by a dot, e.g.