Skip to content

Commit

Permalink
New Resource: azurerm_bot_channel_email (#4389)
Browse files Browse the repository at this point in the history
mbfrahry authored Sep 27, 2019
1 parent b803a22 commit bde8470
Showing 5 changed files with 466 additions and 0 deletions.
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
@@ -196,6 +196,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_batch_account": resourceArmBatchAccount(),
"azurerm_batch_application": resourceArmBatchApplication(),
"azurerm_batch_certificate": resourceArmBatchCertificate(),
"azurerm_bot_channel_email": resourceArmBotChannelEmail(),
"azurerm_bot_channel_slack": resourceArmBotChannelSlack(),
"azurerm_bot_channels_registration": resourceArmBotChannelsRegistration(),
"azurerm_bot_connection": resourceArmBotConnection(),
203 changes: 203 additions & 0 deletions azurerm/resource_arm_bot_channel_email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package azurerm

import (
"fmt"
"log"

"github.com/Azure/azure-sdk-for-go/services/preview/botservice/mgmt/2018-07-12/botservice"
"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmBotChannelEmail() *schema.Resource {
return &schema.Resource{
Create: resourceArmBotChannelEmailCreate,
Read: resourceArmBotChannelEmailRead,
Delete: resourceArmBotChannelEmailDelete,
Update: resourceArmBotChannelEmailUpdate,

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

Schema: map[string]*schema.Schema{
"resource_group_name": azure.SchemaResourceGroupName(),

"location": azure.SchemaLocation(),

"bot_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},

"email_address": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validate.NoEmptyStrings,
},

"email_password": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
ValidateFunc: validate.NoEmptyStrings,
},
},
}
}

func resourceArmBotChannelEmailCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).bot.ChannelClient
ctx := meta.(*ArmClient).StopContext

resourceGroup := d.Get("resource_group_name").(string)
botName := d.Get("bot_name").(string)

if features.ShouldResourcesBeImported() && d.IsNewResource() {
existing, err := client.Get(ctx, resourceGroup, string(botservice.ChannelNameEmailChannel), botName)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("Error checking for presence of creating Channel Email for Bot %q (Resource Group %q): %+v", resourceGroup, botName, err)
}
}
if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_bot_channel_email", *existing.ID)
}
}

channel := botservice.BotChannel{
Properties: botservice.EmailChannel{
Properties: &botservice.EmailChannelProperties{
EmailAddress: utils.String(d.Get("email_address").(string)),
Password: utils.String(d.Get("email_password").(string)),
IsEnabled: utils.Bool(true),
},
ChannelName: botservice.ChannelNameEmailChannel1,
},
Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))),
Kind: botservice.KindBot,
}

if _, err := client.Create(ctx, resourceGroup, botName, botservice.ChannelNameEmailChannel, channel); err != nil {
return fmt.Errorf("Error issuing create request for Channel Email for Bot %q (Resource Group %q): %+v", resourceGroup, botName, err)
}

resp, err := client.Get(ctx, resourceGroup, botName, string(botservice.ChannelNameEmailChannel))
if err != nil {
return fmt.Errorf("Error making get request for Channel Email for Bot %q (Resource Group %q): %+v", resourceGroup, botName, err)
}

if resp.ID == nil {
return fmt.Errorf("Cannot read Channel Email for Bot %q (Resource Group %q): %+v", resourceGroup, botName, err)
}

d.SetId(*resp.ID)

return resourceArmBotChannelEmailRead(d, meta)
}

func resourceArmBotChannelEmailRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).bot.ChannelClient
ctx := meta.(*ArmClient).StopContext

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

botName := id.Path["botServices"]
resp, err := client.Get(ctx, id.ResourceGroup, botName, string(botservice.ChannelNameEmailChannel))
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[INFO] Channel Email for Bot %q (Resource Group %q) was not found - removing from state!", id.ResourceGroup, botName)
d.SetId("")
return nil
}

return fmt.Errorf("Error reading Channel Email for Bot %q (Resource Group %q): %+v", id.ResourceGroup, botName, err)
}

d.Set("resource_group_name", id.ResourceGroup)
d.Set("location", resp.Location)
d.Set("bot_name", botName)

if props := resp.Properties; props != nil {
if channel, ok := props.AsEmailChannel(); ok {
if channelProps := channel.Properties; channelProps != nil {
d.Set("email_address", channelProps.EmailAddress)
}
}
}

return nil
}

func resourceArmBotChannelEmailUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).bot.ChannelClient
ctx := meta.(*ArmClient).StopContext

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

botName := id.Path["botServices"]

channel := botservice.BotChannel{
Properties: botservice.EmailChannel{
Properties: &botservice.EmailChannelProperties{
EmailAddress: utils.String(d.Get("email_address").(string)),
Password: utils.String(d.Get("email_password").(string)),
IsEnabled: utils.Bool(true),
},
ChannelName: botservice.ChannelNameEmailChannel1,
},
Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))),
Kind: botservice.KindBot,
}

if _, err := client.Update(ctx, id.ResourceGroup, botName, botservice.ChannelNameEmailChannel, channel); err != nil {
return fmt.Errorf("Error issuing create request for Channel Email for Bot %q (Resource Group %q): %+v", id.ResourceGroup, botName, err)
}

resp, err := client.Get(ctx, id.ResourceGroup, botName, string(botservice.ChannelNameEmailChannel))
if err != nil {
return fmt.Errorf("Error making get request for Channel Email for Bot %q (Resource Group %q): %+v", id.ResourceGroup, botName, err)
}

if resp.ID == nil {
return fmt.Errorf("Cannot read Channel Email for Bot %q (Resource Group %q): %+v", id.ResourceGroup, botName, err)
}

d.SetId(*resp.ID)

return resourceArmBotChannelEmailRead(d, meta)
}

func resourceArmBotChannelEmailDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).bot.ChannelClient
ctx := meta.(*ArmClient).StopContext

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

botName := id.Path["botServices"]

resp, err := client.Delete(ctx, id.ResourceGroup, botName, string(botservice.ChannelNameEmailChannel))
if err != nil {
if !response.WasNotFound(resp.Response) {
return fmt.Errorf("Error deleting Channel Email for Bot %q (Resource Group %q): %+v", id.ResourceGroup, botName, err)
}
}

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

import (
"fmt"
"net/http"
"os"
"testing"

"github.com/Azure/azure-sdk-for-go/services/preview/botservice/mgmt/2018-07-12/botservice"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func TestAccAzureRMBotChannelEmail_basic(t *testing.T) {
if ok := skipEmailChannel(); ok {
t.Skip("Skipping as one of `ARM_TEST_EMAIL`, AND `ARM_TEST_EMAIL_PASSWORD` was not specified")
}
ri := tf.AccRandTimeInt()
config := testAccAzureRMBotChannelEmail_basicConfig(ri, testLocation())
resourceName := "azurerm_bot_channel_email.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMBotChannelEmailDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMBotChannelEmailExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"email_password",
},
},
},
})
}

func TestAccAzureRMBotChannelEmail_update(t *testing.T) {
if ok := skipEmailChannel(); ok {
t.Skip("Skipping as one of `ARM_TEST_EMAIL`, AND `ARM_TEST_EMAIL_PASSWORD` was not specified")
}
if ok := skipSlackChannel(); ok {
t.Skip("Skipping as one of `ARM_TEST_SLACK_CLIENT_ID`, `ARM_TEST_SLACK_CLIENT_SECRET`, or `ARM_TEST_SLACK_VERIFICATION_TOKEN` was not specified")
}
ri := tf.AccRandTimeInt()
config := testAccAzureRMBotChannelEmail_basicConfig(ri, testLocation())
config2 := testAccAzureRMBotChannelEmail_basicUpdate(ri, testLocation())
resourceName := "azurerm_bot_channel_email.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMBotChannelEmailDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMBotChannelEmailExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"email_password",
},
},
{
Config: config2,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMBotChannelEmailExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"email_password",
},
},
},
})
}

func testCheckAzureRMBotChannelEmailExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Ensure we have enough information in state to look up in API
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

botName := rs.Primary.Attributes["bot_name"]
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
if !hasResourceGroup {
return fmt.Errorf("Bad: no resource group found in state for Bot Channel Email")
}

client := testAccProvider.Meta().(*ArmClient).bot.ChannelClient
ctx := testAccProvider.Meta().(*ArmClient).StopContext

resp, err := client.Get(ctx, resourceGroup, botName, string(botservice.ChannelNameEmailChannel))
if err != nil {
return fmt.Errorf("Bad: Get on botChannelClient: %+v", err)
}

if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("Bad: Bot Channel Email %q (resource group: %q / bot: %q) does not exist", name, resourceGroup, botName)
}

return nil
}
}

func testCheckAzureRMBotChannelEmailDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*ArmClient).bot.ChannelClient
ctx := testAccProvider.Meta().(*ArmClient).StopContext

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

botName := rs.Primary.Attributes["bot_name"]
resourceGroup := rs.Primary.Attributes["resource_group_name"]

resp, err := client.Get(ctx, resourceGroup, botName, string(botservice.ChannelNameEmailChannel))

if err != nil {
return nil
}

if resp.StatusCode != http.StatusNotFound {
return fmt.Errorf("Bot Channel Email still exists:\n%#v", resp.Properties)
}
}

return nil
}

func testAccAzureRMBotChannelEmail_basicConfig(rInt int, location string) string {
template := testAccAzureRMBotChannelsRegistration_basicConfig(rInt, location)
return fmt.Sprintf(`
%s
resource "azurerm_bot_channel_email" "test" {
bot_name = "${azurerm_bot_channels_registration.test.name}"
location = "${azurerm_bot_channels_registration.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
email_address = "%s"
email_password = "%s"
}
`, template, os.Getenv("ARM_TEST_EMAIL"), os.Getenv("ARM_TEST_EMAIL_PASSWORD"))
}

func testAccAzureRMBotChannelEmail_basicUpdate(rInt int, location string) string {
template := testAccAzureRMBotChannelsRegistration_basicConfig(rInt, location)
return fmt.Sprintf(`
%s
resource "azurerm_bot_channel_email" "test" {
bot_name = "${azurerm_bot_channels_registration.test.name}"
location = "${azurerm_bot_channels_registration.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
email_address = "%s"
email_password = "%s"
}
`, template, os.Getenv("ARM_TEST_EMAIL"), os.Getenv("ARM_TEST_EMAIL_PASSWORD"))
}

func skipEmailChannel() bool {
if os.Getenv("ARM_TEST_EMAIL") == "" || os.Getenv("ARM_TEST_EMAIL_PASSWORD") == "" {
return true
}

return false
}
4 changes: 4 additions & 0 deletions website/azurerm.erb
Original file line number Diff line number Diff line change
@@ -652,6 +652,10 @@
<li>
<a href="#">Bot Resources</a>
<ul class="nav">
<li>
<a href="/docs/providers/azurerm/r/bot_channel_email.html">azurerm_bot_channel_email</a>
</li>

<li>
<a href="/docs/providers/azurerm/r/bot_channel_slack.html">azurerm_bot_channel_slack</a>
</li>
70 changes: 70 additions & 0 deletions website/docs/r/bot_channel_email.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_bot_channel_email"
sidebar_current: "docs-azurerm-resource-bot-channel-email"
description: |-
Manages a Email integration for a Bot Channel
---

# azurerm_bot_connection

Manages a Email integration for a Bot Channel

~> **Note** A bot can only have a single Email Channel associated with it.

## Example Usage

```hcl
data "azurerm_client_config" "current" {}
resource "azurerm_resource_group" "example" {
name = "example"
location = "northeurope"
}
resource "azurerm_bot_channels_registration" "example" {
name = "example"
location = "global"
resource_group_name = "${azurerm_resource_group.example.name}"
sku = "F0"
microsoft_app_id = "${data.azurerm_client_config.current.service_principal_application_id}"
}
resource "azurerm_bot_channel_Email" "example" {
bot_name = "${azurerm_bot_channels_registration.example.name}"
location = "${azurerm_bot_channels_registration.example.location}"
resource_group_name = "${azurerm_resource_group.example.name}"
client_id = "exampleId"
client_secret = "exampleSecret"
verification_token = "exampleVerificationToken"
}
```

## Argument Reference

The following arguments are supported:

* `resource_group_name` - (Required) The name of the resource group in which to create the Bot Channel. Changing this forces a new resource to be created.

* `location` - (Required) The supported Azure location where the resource exists. Changing this forces a new resource to be created.

* `bot_name` - (Required) The name of the Bot Resource this channel will be associated with. Changing this forces a new resource to be created.

* `email_address` - (Required) The email address that the Bot will authenticate with.

* `email_password` - (Required) The email password that the the Bot will authenticate with.


## Attributes Reference

The following attributes are exported:

* `id` - The Bot Channel ID.

## Import

The Email Channel for a Bot can be imported using the `resource id`, e.g.

```shell
terraform import azurerm_bot_channel_email.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example/providers/Microsoft.BotService/botServices/example/channels/EmailChannel
```

0 comments on commit bde8470

Please sign in to comment.