Skip to content
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

fix: alert rule and tests association #168

Merged
merged 5 commits into from
May 13, 2024
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
12 changes: 11 additions & 1 deletion docs/resources/alert_rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ resource "thousandeyes_alert_rule" "example_alert_rule" {
- `notify_on_clear` (Boolean) Set to 'true' to trigger the notification when the alert clears.
- `rounds_violating_mode` (String) [ANY or EXACT] Defines whether the same agent(s) must meet the EXACT same threshold in consecutive rounds or not. The default value is ANY.
- `severity` (String) [INFO, MINOR, MAJOR or CRITICAL] The severity level of the alert rule. The default value is INFO.
- `test_ids` (List of Number) The valid test IDs.
- `tests` (Block List) The list of included tests. (see [below for nested schema](#nestedblock--tests))

### Read-Only

- `alert_rule_id` (Number) The unique ID of the alert rule.
- `id` (String) The ID of this resource.
- `rule_id` (Number) The unique ID of the alert rule.
- `test_ids` (List of Number) The valid test IDs.

<a id="nestedblock--notifications"></a>
### Nested Schema for `notifications`
Expand Down Expand Up @@ -88,3 +89,12 @@ Required:
- `integration_type` (String) The integration type, as a string.



<a id="nestedblock--tests"></a>
### Nested Schema for `tests`

Optional:

- `test_id` (Number) The list of unique test IDs.


2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/hashicorp/terraform-plugin-docs v0.9.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0
github.com/stretchr/testify v1.8.4
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.2
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.3
)

require (
Expand Down
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/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.2 h1:j84PPcq3EBRtQxJ/zssiBxCajhPQn+unIY5JhDiBWTo=
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.2/go.mod h1:XQouPCy3dIp81Xzkp9bqu6vg7fmE4QQpA6REsLVTDdE=
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.3 h1:4gCG4SSyhgQsVPuLQl5Jdy4CwdHyyoZkktNTqnfcyJc=
github.com/thousandeyes/thousandeyes-sdk-go/v2 v2.4.3/go.mod h1:XQouPCy3dIp81Xzkp9bqu6vg7fmE4QQpA6REsLVTDdE=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
data "thousandeyes_agent" "amsterdam" {
agent_name = "Amsterdam, Netherlands"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, more ATs for this repo! 💪

}

resource "thousandeyes_alert_rule" "test" {
severity = "MAJOR"
rule_name = "Agent To Server Alert Rule Test"
alert_type = "End-to-End (Server)"
expression = "((loss >= 50%) || (probDetail != \"\") || (avgLatency >= 200 ms))"
minimum_sources = 2
rounds_violating_required = 3
rounds_violating_out_of = 4
}

resource "thousandeyes_agent_to_server" "agent_to_server_test" {
test_name = "Agent To Server Test"
interval = 300
alerts_enabled = true
server = "api.stg.thousandeyes.com"
protocol = "TCP"
port = 443
enabled = true
bgp_measurements = true
use_public_bgp = true
mtu_measurements = true

agents {
agent_id = data.thousandeyes_agent.amsterdam.agent_id
}

alert_rules {
rule_id = thousandeyes_alert_rule.test.id
}
}
34 changes: 34 additions & 0 deletions thousandeyes/acceptance_resources/alert_rule/update_alert_rule.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
data "thousandeyes_agent" "amsterdam" {
agent_name = "Amsterdam, Netherlands"
}

resource "thousandeyes_alert_rule" "test" {
severity = "MAJOR"
rule_name = "Agent To Server Alert Rule Test"
alert_type = "End-to-End (Server)"
expression = "((loss >= 50%) || (probDetail != \"\") || (avgLatency >= 200 ms))"
minimum_sources = 2
rounds_violating_required = 4
rounds_violating_out_of = 4
}

resource "thousandeyes_agent_to_server" "agent_to_server_test" {
test_name = "Agent To Server Test"
interval = 300
alerts_enabled = true
server = "api.stg.thousandeyes.com"
protocol = "TCP"
port = 443
enabled = true
bgp_measurements = true
use_public_bgp = true
mtu_measurements = true

agents {
agent_id = data.thousandeyes_agent.amsterdam.agent_id
}

alert_rules {
rule_id = thousandeyes_alert_rule.test.id
}
}
18 changes: 16 additions & 2 deletions thousandeyes/resource_alert_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ func resourceAlertRule() *schema.Resource {

func resourceAlertRuleRead(d *schema.ResourceData, m interface{}) error {
return GetResource(d, m, func(client *thousandeyes.Client, id int64) (interface{}, error) {
return client.GetAlertRule(id)
var alertRule, err = client.GetAlertRule(id)
if err != nil {
return nil, err
}
alertRule.TestIds = testIds(*alertRule.Tests)
alertRule.Tests = nil
return alertRule, nil
})
}

func resourceAlertRuleUpdate(d *schema.ResourceData, m interface{}) error {
client := m.(*thousandeyes.Client)

log.Printf("[INFO] Updating ThousandEyes Test %s", d.Id())
log.Printf("[INFO] Updating ThousandEyes Alert Rule %s", d.Id())
id, _ := strconv.ParseInt(d.Id(), 10, 64)
// While most ThousandEyes updates only require updated fields and specifically
// disallow some fields on update, Alert Rules actually require the full list of
Expand Down Expand Up @@ -74,3 +80,11 @@ func resourceAlertRuleCreate(d *schema.ResourceData, m interface{}) error {
func buildAlertRuleStruct(d *schema.ResourceData) *thousandeyes.AlertRule {
return ResourceBuildStruct(d, &thousandeyes.AlertRule{}).(*thousandeyes.AlertRule)
}

func testIds(tests []thousandeyes.GenericTest) *[]int64 {
var testIds []int64
for _, test := range tests {
testIds = append(testIds, *test.TestID)
}
return &testIds
}
84 changes: 84 additions & 0 deletions thousandeyes/resource_alert_rule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package thousandeyes

import (
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccThousandEyesAlertRule(t *testing.T) {
var alertRuleResourceName = "thousandeyes_alert_rule.test"
testCases := []struct {
name string
createResourceFile string
updateResourceFile string
checkDestroyFunction func(*terraform.State) error
checkCreateFunc []resource.TestCheckFunc
checkUpdateFunc []resource.TestCheckFunc
}{
{
name: "test_association_maintained_after_alert_rule_update",
createResourceFile: "acceptance_resources/alert_rule/create_test_with_alert_rule.tf",
updateResourceFile: "acceptance_resources/alert_rule/update_alert_rule.tf",
checkDestroyFunction: func(state *terraform.State) error {
resourceList := []ResourceType{
{
Name: "Agent To Server Test",
ResourceName: "thousandeyes_agent_to_server",
GetResource: func(id int64) (interface{}, error) {
return testClient.GetAgentServer(id)
}},
{
Name: "Agent To Server Alert Rule Test",
ResourceName: "thousandeyes_alert_rule",
GetResource: func(id int64) (interface{}, error) {
return testClient.GetAlertRule(id)
}},
}
return testAccCheckResourceDestroy(resourceList, state)
},
checkCreateFunc: []resource.TestCheckFunc{
//alert rule is created
//with 3 required violating rounds
resource.TestCheckResourceAttr(alertRuleResourceName, "rounds_violating_required", "3"),
},
checkUpdateFunc: []resource.TestCheckFunc{
//alert rule is updated
//to 4 required violating rounds
resource.TestCheckResourceAttr(alertRuleResourceName, "rounds_violating_required", "4"),
//and the test association is maintained
resource.TestCheckResourceAttr(alertRuleResourceName, "test_ids.#", "1"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to start adding some comments to these Acceptance tests - the ones that I created also do not have them and they should!
It's not immediate to understand that here we are making sure that if an alertRule is updated, them the tests associated with it are not cleared. Can you add a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried to reflect that in the test name but i guess i failed miserably 😅
i've added the comments, take another look when possible

},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: tc.checkDestroyFunction,
Steps: []resource.TestStep{
{
Config: testAccThousandEyesAlertRuleConfig(tc.createResourceFile),
Check: resource.ComposeTestCheckFunc(tc.checkCreateFunc...),
},
{
Config: testAccThousandEyesAlertRuleConfig(tc.updateResourceFile),
Check: resource.ComposeTestCheckFunc(tc.checkUpdateFunc...),
},
},
})
})
}
}

func testAccThousandEyesAlertRuleConfig(testResource string) string {
content, err := os.ReadFile(testResource)
if err != nil {
panic(err)
}
return string(content)
}
2 changes: 1 addition & 1 deletion thousandeyes/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ var schemas = map[string]*schema.Schema{
"test_ids": {
Type: schema.TypeList,
Description: "The valid test IDs.",
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Expand Down
Loading