Skip to content

Commit

Permalink
feat: New Relic Insights alert channel resource (#73)
Browse files Browse the repository at this point in the history
Signed-off-by: Darren Murray <darren.murray@lacework.net>
  • Loading branch information
dmurray-lacework authored Feb 19, 2021
1 parent 641f7cd commit 5d7877a
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 2 deletions.
7 changes: 7 additions & 0 deletions examples/resource_lacework_alert_channel_newrelic/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
provider "lacework" {}

resource "lacework_alert_channel_newrelic" "example" {
name = "My New Relic Insights Channel Alert Example"
account_id = 2338053
insert_key = "x-xx-xxxxxxxxxxxxxxxxxx"
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/hashicorp/terraform-plugin-test v1.4.3 // indirect
github.com/hashicorp/terraform-svchost v0.0.0-20191119180714-d2e4933b9136 // indirect
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
github.com/lacework/go-sdk v0.2.20-0.20210216214810-cac9fc27f696
github.com/lacework/go-sdk v0.2.20-0.20210219030740-d7242b84a525
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mitchellh/cli v1.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ github.com/lacework/go-sdk v0.2.19-0.20210211001048-e41422624b52 h1:XgcQ1sTXFRqq
github.com/lacework/go-sdk v0.2.19-0.20210211001048-e41422624b52/go.mod h1:yiEjWVHT4TjkZZ1pa9eS8fIfnnoVuzj1VNTIVEIsSKE=
github.com/lacework/go-sdk v0.2.20-0.20210216214810-cac9fc27f696 h1:jd6J6ZjehkBH0MuO9Ttz7jyqTAcC2et5DxM4hV7LI28=
github.com/lacework/go-sdk v0.2.20-0.20210216214810-cac9fc27f696/go.mod h1:yiEjWVHT4TjkZZ1pa9eS8fIfnnoVuzj1VNTIVEIsSKE=
github.com/lacework/go-sdk v0.2.20-0.20210219030740-d7242b84a525 h1:AWsfiGWpdtokfQDuGNhtP6oylCNDEVUaT5febFcJk30=
github.com/lacework/go-sdk v0.2.20-0.20210219030740-d7242b84a525/go.mod h1:yiEjWVHT4TjkZZ1pa9eS8fIfnnoVuzj1VNTIVEIsSKE=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
Expand Down
1 change: 1 addition & 0 deletions lacework/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func Provider() terraform.ResourceProvider {
"lacework_alert_channel_gcp_pub_sub": resourceLaceworkAlertChannelGcpPubSub(),
"lacework_alert_channel_jira_cloud": resourceLaceworkAlertChannelJiraCloud(),
"lacework_alert_channel_jira_server": resourceLaceworkAlertChannelJiraServer(),
"lacework_alert_channel_newrelic": resourceLaceworkAlertChannelNewRelic(),
"lacework_alert_channel_pagerduty": resourceLaceworkAlertChannelPagerDuty(),
"lacework_alert_channel_microsoft_teams": resourceLaceworkAlertChannelMicrosoftTeams(),
"lacework_alert_channel_slack": resourceLaceworkAlertChannelSlack(),
Expand Down
215 changes: 215 additions & 0 deletions lacework/resource_lacework_alert_channel_newrelic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package lacework

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/lacework/go-sdk/api"
)

func resourceLaceworkAlertChannelNewRelic() *schema.Resource {
return &schema.Resource{
Create: resourceLaceworkAlertChannelNewRelicCreate,
Read: resourceLaceworkAlertChannelNewRelicRead,
Update: resourceLaceworkAlertChannelNewRelicUpdate,
Delete: resourceLaceworkAlertChannelNewRelicDelete,

Importer: &schema.ResourceImporter{
State: importLaceworkIntegration,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"intg_guid": {
Type: schema.TypeString,
Computed: true,
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"insert_key": {
Type: schema.TypeString,
Required: true,
},
"created_or_updated_time": {
Type: schema.TypeString,
Computed: true,
},
"created_or_updated_by": {
Type: schema.TypeString,
Computed: true,
},
"type_name": {
Type: schema.TypeString,
Computed: true,
},
"org_level": {
Type: schema.TypeBool,
Computed: true,
},
},
}
}

func resourceLaceworkAlertChannelNewRelicCreate(d *schema.ResourceData, meta interface{}) error {
var (
lacework = meta.(*api.Client)
relic = api.NewNewRelicAlertChannel(d.Get("name").(string),
api.NewRelicChannelData{
AccountID: d.Get("account_id").(int),
InsertKey: d.Get("insert_key").(string),
},
)
)
if !d.Get("enabled").(bool) {
relic.Enabled = 0
}

log.Printf("[INFO] Creating %s integration with data:\n%+v\n", api.NewRelicChannelIntegration, relic)
response, err := lacework.Integrations.CreateNewRelicAlertChannel(relic)
if err != nil {
return err
}

log.Println("[INFO] Verifying server response data")
err = validateNewRelicAlertChannelResponse(&response)
if err != nil {
return err
}

integration := response.Data[0]
d.SetId(integration.IntgGuid)
d.Set("name", integration.Name)
d.Set("intg_guid", integration.IntgGuid)
d.Set("enabled", integration.Enabled == 1)
d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime)
d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy)
d.Set("type_name", integration.TypeName)
d.Set("org_level", integration.IsOrg == 1)

log.Printf("[INFO] Created %s integration with guid: %v\n", api.NewRelicChannelIntegration, integration.IntgGuid)
return nil
}

func resourceLaceworkAlertChannelNewRelicRead(d *schema.ResourceData, meta interface{}) error {
lacework := meta.(*api.Client)

log.Printf("[INFO] Reading %s integration with guid: %v\n", api.NewRelicChannelIntegration, d.Id())
response, err := lacework.Integrations.GetNewRelicAlertChannel(d.Id())
if err != nil {
return err
}

for _, integration := range response.Data {
if integration.IntgGuid == d.Id() {
d.Set("name", integration.Name)
d.Set("intg_guid", integration.IntgGuid)
d.Set("enabled", integration.Enabled == 1)
d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime)
d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy)
d.Set("type_name", integration.TypeName)
d.Set("org_level", integration.IsOrg == 1)
d.Set("account_id", integration.Data.AccountID)
d.Set("insert_key", integration.Data.InsertKey)

log.Printf("[INFO] Read %s integration with guid: %v\n",
api.NewRelicChannelIntegration, integration.IntgGuid)
return nil
}
}

d.SetId("")
return nil
}

func resourceLaceworkAlertChannelNewRelicUpdate(d *schema.ResourceData, meta interface{}) error {
var (
lacework = meta.(*api.Client)
relic = api.NewNewRelicAlertChannel(d.Get("name").(string),
api.NewRelicChannelData{
AccountID: d.Get("account_id").(int),
InsertKey: d.Get("insert_key").(string),
},
)
)

if !d.Get("enabled").(bool) {
relic.Enabled = 0
}

relic.IntgGuid = d.Id()

log.Printf("[INFO] Updating %s integration with data:\n%+v\n", api.NewRelicChannelIntegration, relic)
response, err := lacework.Integrations.UpdateNewRelicAlertChannel(relic)
if err != nil {
return err
}

log.Println("[INFO] Verifying server response data")
err = validateNewRelicAlertChannelResponse(&response)
if err != nil {
return err
}

integration := response.Data[0]
d.Set("name", integration.Name)
d.Set("intg_guid", integration.IntgGuid)
d.Set("enabled", integration.Enabled == 1)
d.Set("created_or_updated_time", integration.CreatedOrUpdatedTime)
d.Set("created_or_updated_by", integration.CreatedOrUpdatedBy)
d.Set("type_name", integration.TypeName)
d.Set("org_level", integration.IsOrg == 1)

log.Printf("[INFO] Updated %s integration with guid: %v\n", api.NewRelicChannelIntegration, d.Id())
return nil
}

func resourceLaceworkAlertChannelNewRelicDelete(d *schema.ResourceData, meta interface{}) error {
lacework := meta.(*api.Client)

log.Printf("[INFO] Deleting %s integration with guid: %v\n", api.NewRelicChannelIntegration, d.Id())
_, err := lacework.Integrations.Delete(d.Id())
if err != nil {
return err
}

log.Printf("[INFO] Deleted %s integration with guid: %v\n", api.NewRelicChannelIntegration, d.Id())
return nil
}

func validateNewRelicAlertChannelResponse(response *api.NewRelicAlertChannelResponse) error {
if len(response.Data) == 0 {
msg := `
Unable to read sever response data. (empty 'data' field)
This was an unexpected behavior, verify that your integration has been
created successfully and report this issue to support@lacework.net
`
return fmt.Errorf(msg)
}

if len(response.Data) > 1 {
msg := `
There is more that one integration inside the server response data.
List of integrations:
`
for _, integration := range response.Data {
msg = msg + fmt.Sprintf("\t%s: %s\n", integration.IntgGuid, integration.Name)
}
msg = msg + unexpectedBehaviorMsg()
return fmt.Errorf(msg)
}

return nil
}
141 changes: 141 additions & 0 deletions lacework/resource_lacework_alert_channel_newrelic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package lacework

import (
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/lacework/go-sdk/api"
)

const (
testAccAlertChannelNewRelicResourceType = "lacework_alert_channel_newrelic"
testAccAlertChannelNewRelicResourceName = "example"

testAccAlertChannelNewRelicAccountID = "ACCOUNT_ID"
testAccAlertChannelNewRelicInsertKey = "INSERT_KEY"
)

func TestAccAlertChannelNewRelic(t *testing.T) {
resourceTypeAndName := fmt.Sprintf("%s.%s",
testAccAlertChannelNewRelicResourceType,
testAccAlertChannelNewRelicResourceName,
)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccAlertChannelNewRelicEnvVarsPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckAlertChannelNewRelicDestroy,
Steps: []resource.TestStep{
{
Config: testAccAlertChannelNewRelicConfig(
true,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckAlertChannelNewRelicExists(resourceTypeAndName),
resource.TestCheckResourceAttr(resourceTypeAndName, "enabled", "true"),
),
},
{
Config: testAccAlertChannelNewRelicConfig(
false,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckAlertChannelNewRelicExists(resourceTypeAndName),
resource.TestCheckResourceAttr(resourceTypeAndName, "enabled", "false"),
),
},
},
})
}

func testAccCheckAlertChannelNewRelicDestroy(s *terraform.State) error {
lacework := testAccProvider.Meta().(*api.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != testAccAlertChannelNewRelicResourceType {
continue
}

response, err := lacework.Integrations.GetNewRelicAlertChannel(rs.Primary.ID)
if err != nil {
return err
}

for _, integration := range response.Data {
if integration.IntgGuid == rs.Primary.ID {
return fmt.Errorf(
"the %s integration (%s) still exists",
api.NewRelicChannelIntegration, rs.Primary.ID,
)
}
}
}

return nil
}

func testAccCheckAlertChannelNewRelicExists(resourceTypeAndName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
lacework := testAccProvider.Meta().(*api.Client)

rs, ok := s.RootModule().Resources[resourceTypeAndName]
if !ok {
return fmt.Errorf("resource (%s) not found", resourceTypeAndName)
}

if rs.Primary.ID == "" {
return fmt.Errorf("resource (%s) ID not set", resourceTypeAndName)
}

response, err := lacework.Integrations.GetNewRelicAlertChannel(rs.Primary.ID)
if err != nil {
return err
}

if len(response.Data) < 1 {
return fmt.Errorf("the %s integration (%s) doesn't exist",
api.NewRelicChannelIntegration, rs.Primary.ID)
}

for _, integration := range response.Data {
if integration.IntgGuid == rs.Primary.ID {
return nil
}
}

return fmt.Errorf("the %s integration (%s) doesn't exist",
api.NewRelicChannelIntegration, rs.Primary.ID)
}
}

func testAccAlertChannelNewRelicEnvVarsPreCheck(t *testing.T) {
if v := os.Getenv(testAccAlertChannelNewRelicAccountID); v == "" {
t.Fatalf("%s must be set for acceptance tests", testAccAlertChannelNewRelicAccountID)
}
if v := os.Getenv(testAccAlertChannelNewRelicInsertKey); v == "" {
t.Fatalf("%s must be set for acceptance tests", testAccAlertChannelNewRelicInsertKey)
}
}

func testAccAlertChannelNewRelicConfig(enabled bool) string {
return fmt.Sprintf(`
resource "%s" "%s" {
name = "integration test"
enabled = %t
account_id = "%s"
insert_key = "%s"
}
`,
testAccAlertChannelNewRelicResourceType,
testAccAlertChannelNewRelicResourceName,
enabled,
os.Getenv(testAccAlertChannelNewRelicAccountID),
os.Getenv(testAccAlertChannelNewRelicInsertKey),
)
}
Loading

0 comments on commit 5d7877a

Please sign in to comment.