Skip to content

Alert policy order #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions opsgenie/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func Provider() *schema.Provider {
"opsgenie_maintenance": resourceOpsgenieMaintenance(),
"opsgenie_heartbeat": resourceOpsgenieHeartbeat(),
"opsgenie_alert_policy": resourceOpsGenieAlertPolicy(),
"opsgenie_alert_policy_order": resourceOpsGeniePoliciesOrder(),
"opsgenie_service_incident_rule": resourceOpsGenieServiceIncidentRule(),
"opsgenie_incident_template": resourceOpsgenieIncidentTemplate(),
},
Expand Down
131 changes: 131 additions & 0 deletions opsgenie/resource_opsgenie_alert_policies_order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package opsgenie

import (
"context"
"log"
"sort"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/opsgenie/opsgenie-go-sdk-v2/policy"
)

func resourceOpsGeniePoliciesOrder() *schema.Resource {
return &schema.Resource{
CreateContext: resourceOpsGeniePoliciesOrderSet,
ReadContext: resourceOpsGeniePoliciesOrderRead,
UpdateContext: resourceOpsGeniePoliciesOrderSet,
DeleteContext: resourceOpsGeniePoliciesOrderDelete,
Schema: map[string]*schema.Schema{
"team_id": {
Type: schema.TypeString,
Optional: true,
},
"policy_ids": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func resourceOpsGeniePoliciesOrderRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// The map makes it easier to check if an id is set in the order list
policy_ids := make(map[string]struct{})
for _, id := range d.Get("policy_ids").([]interface{}) {
policy_ids[id.(string)] = struct{}{}
}

current_policy_ids, err := readPoliciesOrder(d.Get("team_id").(string), meta)
if err != nil {
return diag.FromErr(err)
}

// Ignore current ids that aren't set in the order list
// Avoids systematic diff when other policies aren't ordered through the ressource
// (which should be avoided anyway)
filtered_current_policy_ids := make([]string, len(policy_ids))
idx := 0
for _, id := range current_policy_ids {
_, ok := policy_ids[id]
if ok {
filtered_current_policy_ids[idx] = id
idx++
}
}

d.Set("policy_ids", filtered_current_policy_ids)

return nil
}

func resourceOpsGeniePoliciesOrderSet(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := policy.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return diag.FromErr(err)
}

team_id := d.Get("team_id").(string)
policy_ids := d.Get("policy_ids").([]interface{})

for i, policy_id := range policy_ids {
orderRequest := &policy.ChangeOrderRequest{
Id: policy_id.(string),
Type: policy.AlertPolicy,
TargetIndex: i + 1,
}
if d.Get("team_id").(string) != "" {
orderRequest.TeamId = d.Get("team_id").(string)
}
log.Printf("[INFO] Updating order for Alert Policy '%s' with index %d", policy_id, i)
_, err = client.ChangeOrder(context.Background(), orderRequest)
if err != nil {
d.Partial(true)
return diag.FromErr(err)
}
}

d.SetId(team_id)

return nil
}

func resourceOpsGeniePoliciesOrderDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return nil
}

func readPoliciesOrder(team_id string, meta interface{}) ([]string, error) {
log.Printf("[INFO] Reading OpsGenie Alert Policies for team %s", team_id)

client, err := policy.NewClient(meta.(*OpsgenieClient).client.Config)
if err != nil {
return nil, err
}

listRequest := &policy.ListAlertPoliciesRequest{}
if team_id != "" {
listRequest.TeamId = team_id
}

policiesRes, err := client.ListAlertPolicies(context.Background(), listRequest)
if err != nil {
return nil, err
}

policies := policiesRes.Policies

sort.SliceStable(policies, func(i, j int) bool {
return policies[i].Order < policies[j].Order
})

policy_ids := make([]string, len(policies))

for i, policy := range policies {
policy_ids[i] = policy.Id
}

return policy_ids, nil
}
105 changes: 105 additions & 0 deletions opsgenie/resource_opsgenie_alert_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"sort"
"strings"
"testing"

Expand Down Expand Up @@ -112,6 +113,26 @@ func TestAccOpsGenieAlertPolicy_complete(t *testing.T) {
})
}

func TestAccOpsGenieAlertPolicy_order(t *testing.T) {
randomTeam := acctest.RandString(6)
randomAlertPolicyName := acctest.RandString(6)
policiesOrder := []int{2, 3, 1}

config := testAccOpsGenieAlertPolicy_order(randomTeam, randomAlertPolicyName, policiesOrder)

resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckOpsGenieAlertPolicyOrder("opsgenie_alert_policy_order.test", randomAlertPolicyName, policiesOrder),
),
},
},
})
}

func testCheckOpsGenieAlertPolicyDestroy(s *terraform.State) error {
client, err := policy.NewClient(testAccProvider.Meta().(*OpsgenieClient).client.Config)
if err != nil {
Expand Down Expand Up @@ -165,6 +186,54 @@ func testCheckOpsGenieAlertPolicyExists(name string) resource.TestCheckFunc {
}
}

func testCheckOpsGenieAlertPolicyOrder(resName, policyName string, policiesOrder []int) resource.TestCheckFunc {
return func(s *terraform.State) error {

fmt.Printf("Running testCheckOpsGenieAlertPolicyOrder")
rs, ok := s.RootModule().Resources[resName]
if !ok {
return fmt.Errorf("Not found: %s", resName)
}

client, err := policy.NewClient(testAccProvider.Meta().(*OpsgenieClient).client.Config)
if err != nil {
return err
}

listRequest := policy.ListAlertPoliciesRequest{
TeamId: rs.Primary.Attributes["team_id"],
}

res, err := client.ListAlertPolicies(context.Background(), &listRequest)
if err != nil {
return err
}

currentPolicies := res.Policies
sort.SliceStable(currentPolicies, func(i, j int) bool {
return currentPolicies[i].Order < currentPolicies[j].Order
})

currentIdx := 0
for _, expectedIdx := range policiesOrder {
expectedPolicyName := fmt.Sprintf("genie-alert-policy-%s-%d", policyName, expectedIdx)
for _, currentPolicy := range currentPolicies {
if currentPolicy.Name == expectedPolicyName {
if currentIdx != expectedIdx {
return fmt.Errorf(
"Bad: Policy %s should have index %d, got %d",
currentPolicy.Name, expectedIdx, currentIdx)
}
currentIdx++
break
}
}
}

return nil
}
}

func testAccOpsGenieAlertPolicy_basic(alertPolicyName string) string {
return fmt.Sprintf(`
resource "opsgenie_alert_policy" "test" {
Expand Down Expand Up @@ -246,3 +315,39 @@ func testAccOpsGenieAlertPolicy_complete(randomTeam, randomAlertPolicyName strin
`, randomTeam, randomAlertPolicyName)

}

func testAccOpsGenieAlertPolicy_order(randomTeam, randomAlertPolicyName string, policiesOrder []int) string {
resources := fmt.Sprintf(`
resource "opsgenie_team" "test" {
name = "genieteam-%s"
description = "This team deals with all the things"
}
`, randomTeam)

for i := 1; i <= len(policiesOrder); i++ {
resources += fmt.Sprintf(`
resource "opsgenie_alert_policy" "test%[2]d" {
name = "genie-alert-policy-%[1]s-%[2]d"
policy_description = "Alert policy #%[2]d for the team."
message = "This is a test message"
team_id = opsgenie_team.test.id
filter {}
}
`, randomAlertPolicyName, i)
}

policyIds := ""
for _, i := range policiesOrder {
policyIds += fmt.Sprintf(`
opsgenie_alert_policy.test%d.id,
`, i)
}

resources += fmt.Sprintf(`
resource "opsgenie_alert_policy_order" "test" {
team_id = opsgenie_team.test.id
policy_ids = [%s]
`, policyIds)

return resources
}