Skip to content

Commit

Permalink
fix: Migrate Cisco webex alert channel to API v2 (#193)
Browse files Browse the repository at this point in the history
***Issue***: https://lacework.atlassian.net/browse/ALLY-638?atlOrigin=eyJpIjoiZWQwNzA2NTc0OTc5NGEwMWIzNDYwMzNkYWNhZmQ4MTUiLCJwIjoiaiJ9

***Description:***
Migrate the cisco webex alert channel to use API v2

***Additional Info:***
#147
  • Loading branch information
vatasha authored Oct 12, 2021
1 parent a27565c commit 66e8251
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 241 deletions.
37 changes: 35 additions & 2 deletions examples/resource_lacework_alert_channel_cisco_webex/main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
terraform {
required_providers {
lacework = {
source = "lacework/lacework"
}
}
}

provider "lacework" {}

variable "channel_name" {
type = string
default = "My Cisco Webex Channel Alert Example"
}

variable "webhook_url" {
type = string
sensitive = true
}


resource "lacework_alert_channel_cisco_webex" "example" {
name = "My Cisco Webex Channel Alert Example"
webhook_url = "https://webexapis.com/v1/webhooks/incoming/api-token"
name = var.channel_name
webhook_url = var.webhook_url
// test_integration input is used in this example only for testing
// purposes, it help us avoid sending a "test" request to the
// system we are integrating to. In production, this should remain
// turned on ("true") which is the default setting
test_integration = false
}

output "channel_name" {
value = var.channel_name
}

output "webhook_url" {
value = var.webhook_url
sensitive = true
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.8.0
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
github.com/lacework/go-sdk v0.16.1-0.20211007142812-1a816c9f8b7d
github.com/lacework/go-sdk v0.17.1-0.20211010051859-9481999f2fae
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
github.com/lacework/go-sdk v0.16.1-0.20211007142812-1a816c9f8b7d h1:cZsvsbiAXzpxO1mnelHuoRzeye4FlMc0USBsAZzaJgQ=
github.com/lacework/go-sdk v0.16.1-0.20211007142812-1a816c9f8b7d/go.mod h1:izb0r7jZ9EA1y4O4P8Cq7b3coQzmry2TizQ0DKXLEOg=
github.com/lacework/go-sdk v0.17.1-0.20211010051859-9481999f2fae h1:fNEQQjYlPwe8sKDc56299L6Y7T7AWvJjh7Pygojedo4=
github.com/lacework/go-sdk v0.17.1-0.20211010051859-9481999f2fae/go.mod h1:izb0r7jZ9EA1y4O4P8Cq7b3coQzmry2TizQ0DKXLEOg=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
Expand Down
50 changes: 50 additions & 0 deletions integration/resource_lacework_alert_channel_cisco_webex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package integration

import (
"testing"

"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)

// TestAlertChannelCiscoWebexCreate applies integration terraform:
// => '../examples/resource_lacework_alert_channel_cisco_webex'
//
// It uses the go-sdk to verify the created integration,
// applies an update with new alert channel name and destroys it
func TestAlertChannelCiscoWebexCreate(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/resource_lacework_alert_channel_cisco_webex",
Vars: map[string]interface{}{
"channel_name": "Cisco Webex Alert Channel Example",
"webhook_url": "https://webexapis.com/v1/webhooks/incoming/api-token",
},
})
defer terraform.Destroy(t, terraformOptions)

// Create new Cisco webex Alert Channel
create := terraform.InitAndApplyAndIdempotent(t, terraformOptions)
assert.Equal(t, "Cisco Webex Alert Channel Example", GetIntegrationName(create))

// Update Cisco Alert Channel
terraformOptions.Vars = map[string]interface{}{
"channel_name": "Cisco Webex Alert Channel Example Updated",
"webhook_url": "https://webexapis.com/v1/webhooks/incoming/api-token",
}

update := terraform.Apply(t, terraformOptions)

// Verify that the lacework integration was created with the correct information
updateProps := GetAlertChannelProps(update)
if data, ok := updateProps.Data.Data.(map[string]interface{}); ok {
assert.True(t, ok)
assert.Equal(t, "Cisco Webex Alert Channel Example Updated", updateProps.Data.Name)
assert.Equal(t, "https://webexapis.com/v1/webhooks/incoming/api-token", data["webhook"])
}

// Verify that the terraform resource has the correct information as expected
actualChannelName := terraform.Output(t, terraformOptions, "channel_name")
actualWebhookUrl := terraform.Output(t, terraformOptions, "webhook_url")
assert.Equal(t, "Cisco Webex Alert Channel Example Updated", actualChannelName)
assert.Equal(t, "https://webexapis.com/v1/webhooks/incoming/api-token", actualWebhookUrl)
}
143 changes: 51 additions & 92 deletions lacework/resource_lacework_alert_channel_cisco_webex.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package lacework

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -21,21 +20,25 @@ func resourceLaceworkAlertChannelCiscoWebex() *schema.Resource {

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
Description: "The name of the alert channel",
},
"intg_guid": {
Type: schema.TypeString,
Computed: true,
Type: schema.TypeString,
Computed: true,
Description: "The unique identifier of the integration",
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "The state of the external integration",
},
"webhook_url": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
Description: "The webhook url for the integration",
},
"test_integration": {
Type: schema.TypeBool,
Expand Down Expand Up @@ -66,86 +69,75 @@ func resourceLaceworkAlertChannelCiscoWebex() *schema.Resource {
func resourceLaceworkAlertChannelCiscoWebexCreate(d *schema.ResourceData, meta interface{}) error {
var (
lacework = meta.(*api.Client)
webex = api.NewCiscoWebexAlertChannel(d.Get("name").(string),
api.CiscoWebexChannelData{
WebhookURL: d.Get("webhook_url").(string),
webex = api.NewAlertChannel(d.Get("name").(string),
api.CiscoSparkWebhookAlertChannelType,
api.CiscoSparkWebhookDataV2{
Webhook: d.Get("webhook_url").(string),
},
)
)
if !d.Get("enabled").(bool) {
webex.Enabled = 0
}

log.Printf("[INFO] Creating %s integration with data:\n%+v\n", api.CiscoWebexChannelIntegration, webex)
response, err := lacework.Integrations.CreateCiscoWebexAlertChannel(webex)
log.Printf("[INFO] Creating %s integration with data:\n%+v\n", api.CiscoSparkWebhookAlertChannelType, webex)
response, err := lacework.V2.AlertChannels.Create(webex)
if err != nil {
return err
}

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

integration := response.Data[0]
integration := response.Data
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("type_name", integration.Type)
d.Set("org_level", integration.IsOrg == 1)

if d.Get("test_integration").(bool) {
log.Printf("[INFO] Testing %s integration for guid %s\n", api.CiscoWebexChannelIntegration, d.Id())
log.Printf("[INFO] Testing %s integration for guid %s\n", api.CiscoSparkWebhookAlertChannelType, d.Id())
if err := VerifyAlertChannelAndRollback(d.Id(), lacework); err != nil {
return err
}
log.Printf("[INFO] Tested %s integration with guid %s successfully\n", api.CiscoWebexChannelIntegration, d.Id())
log.Printf("[INFO] Tested %s integration with guid %s successfully\n", api.CiscoSparkWebhookAlertChannelType, d.Id())
}

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

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

log.Printf("[INFO] Reading %s integration with guid %s\n", api.CiscoWebexChannelIntegration, d.Id())
response, err := lacework.Integrations.GetCiscoWebexAlertChannel(d.Id())
log.Printf("[INFO] Reading %s integration with guid %s\n", api.CiscoSparkWebhookAlertChannelType, d.Id())
response, err := lacework.V2.AlertChannels.GetCiscoSparkWebhook(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("webhook_url", integration.Data.WebhookURL)

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

d.SetId("")
d.Set("name", response.Data.Name)
d.Set("intg_guid", response.Data.IntgGuid)
d.Set("enabled", response.Data.Enabled == 1)
d.Set("created_or_updated_time", response.Data.CreatedOrUpdatedTime)
d.Set("created_or_updated_by", response.Data.CreatedOrUpdatedBy)
d.Set("type_name", response.Data.Type)
d.Set("org_level", response.Data.IsOrg == 1)
d.Set("webhook_url", response.Data.Data.Webhook)

log.Printf("[INFO] Read %s integration with guid %s\n",
api.CiscoSparkWebhookAlertChannelType, response.Data.IntgGuid)
return nil
}

func resourceLaceworkAlertChannelCiscoWebexUpdate(d *schema.ResourceData, meta interface{}) error {
var (
lacework = meta.(*api.Client)
webex = api.NewCiscoWebexAlertChannel(d.Get("name").(string),
api.CiscoWebexChannelData{
WebhookURL: d.Get("webhook_url").(string),
webex = api.NewAlertChannel(d.Get("name").(string),
api.CiscoSparkWebhookAlertChannelType,
api.CiscoSparkWebhookDataV2{
Webhook: d.Get("webhook_url").(string),
},
)
)
Expand All @@ -156,75 +148,42 @@ func resourceLaceworkAlertChannelCiscoWebexUpdate(d *schema.ResourceData, meta i

webex.IntgGuid = d.Id()

log.Printf("[INFO] Updating %s integration with data:\n%+v\n", api.CiscoWebexChannelIntegration, webex)
response, err := lacework.Integrations.UpdateCiscoWebexAlertChannel(webex)
log.Printf("[INFO] Updating %s integration with data:\n%+v\n", api.CiscoSparkWebhookAlertChannelType, webex)
response, err := lacework.V2.AlertChannels.UpdateCiscoSparkWebhook(webex)
if err != nil {
return err
}

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

integration := response.Data[0]
integration := response.Data
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("type_name", integration.Type)
d.Set("org_level", integration.IsOrg == 1)

if d.Get("test_integration").(bool) {
log.Printf("[INFO] Testing %s integration for guid %s\n", api.CiscoWebexChannelIntegration, d.Id())
log.Printf("[INFO] Testing %s integration for guid %s\n", api.CiscoSparkWebhookAlertChannelType, d.Id())
if err := lacework.V2.AlertChannels.Test(d.Id()); err != nil {
return err
}
log.Printf("[INFO] Tested %s integration with guid %s successfully\n", api.CiscoWebexChannelIntegration, d.Id())
log.Printf("[INFO] Tested %s integration with guid %s successfully\n", api.CiscoSparkWebhookAlertChannelType, d.Id())
}

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

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

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

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

func validateCiscoWebexAlertChannelResponse(response *api.CiscoWebexAlertChannelResponse) 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)
}

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

0 comments on commit 66e8251

Please sign in to comment.