Skip to content

Commit

Permalink
Incident template API implementation (#178)
Browse files Browse the repository at this point in the history
* Adding implementation of incident template API
  • Loading branch information
GarimaDamani authored Sep 17, 2020
1 parent 4ed3e8b commit 49ed450
Show file tree
Hide file tree
Showing 15 changed files with 1,786 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.4.9 (September 17, 2020)
NEW RESOURCE:
* Incident Template implemented (#178)


## 0.4.8 (September 4, 2020)
NEW RESOURCE:
* Notification rule implemented (#121)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ go 1.14
require (
github.com/hashicorp/go-retryablehttp v0.6.6
github.com/hashicorp/terraform-plugin-sdk v1.15.0
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200820123717-3bcc8ea32b68
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200911071451-adf7a1c79aac
github.com/pkg/errors v0.8.1
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200820123717-3bcc8ea32b68 h1:aeMcivVe6oeKG+2eIml82VULDUIRLXfqEDNmfjesf5o=
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200820123717-3bcc8ea32b68/go.mod h1:VOkJ7STzYj+nXRhMcBTcmt8uZZ17KZKJdZtJpgHLbT8=
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200911071451-adf7a1c79aac h1:SxtpD9CfTncbSkcNVYeqW46DXJqz5b7HH8/BB43D+h0=
github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.2-0.20200911071451-adf7a1c79aac/go.mod h1:VOkJ7STzYj+nXRhMcBTcmt8uZZ17KZKJdZtJpgHLbT8=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
1 change: 1 addition & 0 deletions opsgenie/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func Provider() terraform.ResourceProvider {
"opsgenie_heartbeat": resourceOpsgenieHeartbeat(),
"opsgenie_alert_policy": resourceOpsGenieAlertPolicy(),
"opsgenie_service_incident_rule": resourceOpsGenieServiceIncidentRule(),
"opsgenie_incident_template": resourceOpsgenieIncidentTemplate(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
216 changes: 216 additions & 0 deletions opsgenie/resource_opsgenie_incident_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package opsgenie

import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/opsgenie/opsgenie-go-sdk-v2/incident"
"log"
)

func resourceOpsgenieIncidentTemplate() *schema.Resource {
return &schema.Resource{
Create: resourceOpsgenieIncidentTemplateCreate,
Read: resourceOpsgenieIncidentTemplateRead,
Update: resourceOpsgenieIncidentTemplateUpdate,
Delete: resourceOpsgenieIncidentTemplateDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"message": {
Type: schema.TypeString,
Required: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"tags": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"details": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"priority": {
Type: schema.TypeString,
Required: true,
},
"impacted_services": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"stakeholder_properties": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enable": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"message": {
Type: schema.TypeString,
Required: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(1, 15000),
},
},
},
},
},
}
}

func resourceOpsgenieIncidentTemplateCreate(d *schema.ResourceData, meta interface{}) error {
client, err := incident.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return err
}
createRequest := &incident.CreateIncidentTemplateRequest{
Name: d.Get("name").(string),
Message: d.Get("message").(string),
Description: d.Get("description").(string),
Tags: expandOpsgenieIncidentTemplateTags(d.Get("tags").(*schema.Set)),
Details: expandOpsgenieIncidentTemplateDetails(d.Get("details").(map[string]interface{})),
Priority: incident.Priority(d.Get("priority").(string)),
ImpactedServices: expandOpsgenieIncidentTemplateImpactedServices(d.Get("impacted_services").(*schema.Set)),
StakeholderProperties: expandOpsgenieIncidentTemplateStakeholderProperties(d.Get("stakeholder_properties").([]interface{})),
}
result, err := client.CreateIncidentTemplate(context.Background(), createRequest)
if err != nil {
return err
}
d.SetId(result.IncidentTemplateId)
return resourceOpsgenieIncidentTemplateRead(d, meta)
}

func resourceOpsgenieIncidentTemplateRead(d *schema.ResourceData, meta interface{}) error {
client, err := incident.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return err
}
result, err := client.GetIncidentTemplate(context.Background(), &incident.GetIncidentTemplateRequest{})
if err != nil {
return err
}
if result != nil {
for _, value := range result.IncidentTemplates["incidentTemplates"] {
if d.Id() == value.IncidentTemplateId {
d.Set("name", value.Name)
d.Set("id", value.IncidentTemplateId)
d.Set("message", value.Message)
d.Set("tags", value.Tags)
d.Set("description", value.Description)
d.Set("details", value.Details)
d.Set("priority", value.Priority)
d.Set("stakeholderProperties", value.StakeholderProperties)
d.Set("impactedServices", value.ImpactedServices)
break
}
}
} else {
d.SetId("")
log.Printf("[INFO] Incident template not found")
}
return nil
}

func resourceOpsgenieIncidentTemplateUpdate(d *schema.ResourceData, meta interface{}) error {
client, err := incident.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return err
}
updateRequest := &incident.UpdateIncidentTemplateRequest{
IncidentTemplateId: d.Id(),
Name: d.Get("name").(string),
Message: d.Get("message").(string),
Description: d.Get("description").(string),
Tags: expandOpsgenieIncidentTemplateTags(d.Get("tags").(*schema.Set)),
Details: expandOpsgenieIncidentTemplateDetails(d.Get("details").(map[string]interface{})),
Priority: incident.Priority(d.Get("priority").(string)),
ImpactedServices: expandOpsgenieIncidentTemplateImpactedServices(d.Get("impacted_services").(*schema.Set)),
StakeholderProperties: expandOpsgenieIncidentTemplateStakeholderProperties(d.Get("stakeholder_properties").([]interface{})),
}
_, err = client.UpdateIncidentTemplate(context.Background(), updateRequest)
if err != nil {
return err
}
return nil
}

func resourceOpsgenieIncidentTemplateDelete(d *schema.ResourceData, meta interface{}) error {
client, err := incident.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return err
}
deleteRequest := &incident.DeleteIncidentTemplateRequest{IncidentTemplateId: d.Id()}
_, err = client.DeleteIncidentTemplate(context.Background(), deleteRequest)
if err != nil {
return err
}
return nil
}

func expandOpsgenieIncidentTemplateTags(input *schema.Set) []string {
tags := make([]string, len(input.List()))
if input != nil {
for k, v := range input.List() {
tags[k] = v.(string)
}
}
return tags
}

func expandOpsgenieIncidentTemplateDetails(input map[string]interface{}) map[string]string {
details := make(map[string]string)
if input != nil {
for k, v := range input {
details[k] = v.(string)
}
}
return details
}

func expandOpsgenieIncidentTemplateImpactedServices(input *schema.Set) []string {
impactedService := make([]string, len(input.List()))
if input != nil {
for k, v := range input.List() {
impactedService[k] = v.(string)
}
}
return impactedService
}

func expandOpsgenieIncidentTemplateStakeholderProperties(input []interface{}) incident.StakeholderProperties {
stakeholderProperties := incident.StakeholderProperties{}
if input != nil {
for _, v := range input {
config := v.(map[string]interface{})
enable := config["enable"].(bool)
stakeholderProperties.Enable = &enable
stakeholderProperties.Message = config["message"].(string)
stakeholderProperties.Description = config["description"].(string)
}
}
return stakeholderProperties
}
146 changes: 146 additions & 0 deletions opsgenie/resource_opsgenie_incident_template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package opsgenie

import (
"context"
"errors"
"fmt"
"log"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
ogClient "github.com/opsgenie/opsgenie-go-sdk-v2/client"
"github.com/opsgenie/opsgenie-go-sdk-v2/incident"
)

func init() {
resource.AddTestSweepers("opsgenie_incident_template", &resource.Sweeper{
Name: "opsgenie_incident_template",
F: testSweepIncidentTemplate,
})
}

func testSweepIncidentTemplate(region string) error {
meta, err := sharedConfigForRegion()
if err != nil {
return err
}
client, err := incident.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return err
}
result, err := client.GetIncidentTemplate(context.Background(), &incident.GetIncidentTemplateRequest{})
if err != nil {
return err
}
if result != nil {
for _, value := range result.IncidentTemplates["incidentTemplates"] {
if strings.HasPrefix(value.Name, "genietest-incident-template-") {
log.Printf("Destroying incident template %s", value.Name)
deleteRequest := incident.DeleteIncidentTemplateRequest{IncidentTemplateId: value.IncidentTemplateId}
if _, err := client.DeleteIncidentTemplate(context.Background(), &deleteRequest); err != nil {
return err
}
break
}
}
}
return nil
}

func TestAccOpsGenieIncidentTemplate_basic(t *testing.T) {
config := testAccOpsGenieIncidentTemplate_basic(acctest.RandString(6))
resource.Test(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testCheckOpsGenieIncidentTemplateDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckOpsGenieIncidentTemplateExists(),
),
},
},
})
}

func testCheckOpsGenieIncidentTemplateDestroy(s *terraform.State) error {
client, err := incident.NewClient(testAccProvider.Meta().(*OpsgenieClient).client.Config)
if err != nil {
return err
}
for _, rs := range s.RootModule().Resources {
if rs.Type != "opsgenie_incident_template" {
continue
}
result, err := client.GetIncidentTemplate(context.Background(), &incident.GetIncidentTemplateRequest{})
if err != nil {
x := err.(*ogClient.ApiError)
if x.StatusCode != 404 {
return errors.New(fmt.Sprintf("Incident template still exists: %s", x.Error()))
}
} else if result != nil {
for _, value := range result.IncidentTemplates["incidentTemplates"] {
if strings.HasPrefix(value.Name, "genietest-incident-template-") {
return fmt.Errorf("incident template still exists(it shouldn't exist)")
}
}
}
}
return nil
}

func testCheckOpsGenieIncidentTemplateExists() resource.TestCheckFunc {
return func(s *terraform.State) error {
client, err := incident.NewClient(testAccProvider.Meta().(*OpsgenieClient).client.Config)
if err != nil {
return err
}
result, err := client.GetIncidentTemplate(context.Background(), &incident.GetIncidentTemplateRequest{})
if err != nil && result != nil {
for _, value := range result.IncidentTemplates["incidentTemplates"] {
if strings.HasPrefix(value.Name, "genietest-incident-template-") {
log.Printf("Incident template found.")
return nil
}
}
return fmt.Errorf("incident template does not exist (and it should)")
} else {
return err
}
}
}

func testAccOpsGenieIncidentTemplate_basic(randomName string) string {
return fmt.Sprintf(`
resource "opsgenie_team" "test" {
name = "genietest-team-%s"
description = "This team deals with all the things"
}
resource "opsgenie_service" "test" {
name = "genietest-service-%s"
team_id = opsgenie_team.test.id
}
resource "opsgenie_incident_template" "test" {
name = "genietest-incident-template-%s"
message = "Incident Message"
priority = "P2"
stakeholder_properties {
enable = true
message = "Stakeholder Message"
description = "Stakeholder Description"
}
tags = ["tag1", "tag2"]
description = "Incident Description"
details = {
key1 = "value1"
key2 = "value2"
}
impacted_services = [
opsgenie_service.test.id
]
}
`, randomName, randomName, randomName)
}
Loading

0 comments on commit 49ed450

Please sign in to comment.