Skip to content

Commit

Permalink
Add option in IoTHub to Enable Fallback Route (#2764)
Browse files Browse the repository at this point in the history
Added the option to specify if the IoTHub fallback route should be enabled or not.
It defaults to enabled since the Azure Portal, CLI or ARM all default to true. This is a change in the behaviour of Terraform since Terraform used to default to disabled.
See also issue #2719
  • Loading branch information
BlueBasher authored and katbyte committed Feb 22, 2019
1 parent 42e3a95 commit 9bd7bd8
Show file tree
Hide file tree
Showing 12 changed files with 5,735 additions and 20 deletions.
2 changes: 1 addition & 1 deletion azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2016-05-15/dtl"
"github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub"
"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
"github.com/Azure/azure-sdk-for-go/services/iothub/mgmt/2018-04-01/devices"
keyVault "github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
"github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2018-02-14/keyvault"
"github.com/Azure/azure-sdk-for-go/services/logic/mgmt/2016-06-01/logic"
Expand All @@ -40,6 +39,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/preview/devspaces/mgmt/2018-06-01-preview/devspaces"
"github.com/Azure/azure-sdk-for-go/services/preview/dns/mgmt/2018-03-01-preview/dns"
"github.com/Azure/azure-sdk-for-go/services/preview/eventgrid/mgmt/2018-09-15-preview/eventgrid"
"github.com/Azure/azure-sdk-for-go/services/preview/iothub/mgmt/2018-12-01-preview/devices"
"github.com/Azure/azure-sdk-for-go/services/preview/mariadb/mgmt/2018-06-01-preview/mariadb"
"github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2018-03-01/insights"
"github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi"
Expand Down
130 changes: 112 additions & 18 deletions azurerm/resource_arm_iothub.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"context"
"fmt"
"log"
"regexp"
"strconv"
"time"

"strings"

"github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub"
"github.com/Azure/azure-sdk-for-go/services/iothub/mgmt/2018-04-01/devices"
"github.com/Azure/azure-sdk-for-go/services/preview/iothub/mgmt/2018-12-01-preview/devices"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
Expand Down Expand Up @@ -192,8 +192,9 @@ func resourceArmIotHub() *schema.Resource {
Optional: true,
DiffSuppressFunc: suppress.CaseDifference,
ValidateFunc: validation.StringInSlice([]string{
string(eventhub.Avro),
string(eventhub.AvroDeflate),
string(devices.Avro),
string(devices.AvroDeflate),
string(devices.JSON),
}, true),
},
"file_name_format": {
Expand All @@ -211,9 +212,12 @@ func resourceArmIotHub() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 64),
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(
regexp.MustCompile("^[-_.a-zA-Z0-9]{1,64}$"),
"Route Name name can only include alphanumeric characters, periods, underscores, hyphens, has a maximum length of 64 characters, and must be unique.",
),
},
"source": {
Type: schema.TypeString,
Expand Down Expand Up @@ -248,6 +252,50 @@ func resourceArmIotHub() *schema.Resource {
},
},

"fallback_route": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"source": {
Type: schema.TypeString,
Optional: true,
Default: "DeviceMessages",
ValidateFunc: validation.StringInSlice([]string{
"DeviceJobLifecycleEvents",
"DeviceLifecycleEvents",
"DeviceMessages",
"Invalid",
"TwinChangeEvents",
}, false),
},
"condition": {
// The condition is a string value representing device-to-cloud message routes query expression
// https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-query-language#device-to-cloud-message-routes-query-expressions
Type: schema.TypeString,
Optional: true,
Default: "true",
},
"endpoint_names": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringLenBetween(0, 64),
},
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
},
},
},

"tags": tagsSchema(),
},
}
Expand Down Expand Up @@ -292,6 +340,7 @@ func resourceArmIotHubCreateUpdate(d *schema.ResourceData, meta interface{}) err
location := azureRMNormalizeLocation(d.Get("location").(string))
skuInfo := expandIoTHubSku(d)
tags := d.Get("tags").(map[string]interface{})
fallbackRoute := expandIoTHubFallbackRoute(d)

endpoints, err := expandIoTHubEndpoints(d, subscriptionID)
if err != nil {
Expand All @@ -306,8 +355,9 @@ func resourceArmIotHubCreateUpdate(d *schema.ResourceData, meta interface{}) err
Sku: skuInfo,
Properties: &devices.IotHubProperties{
Routing: &devices.RoutingProperties{
Endpoints: endpoints,
Routes: routes,
Endpoints: endpoints,
Routes: routes,
FallbackRoute: fallbackRoute,
},
},
Tags: expandTags(tags),
Expand All @@ -328,6 +378,7 @@ func resourceArmIotHubCreateUpdate(d *schema.ResourceData, meta interface{}) err
}

d.SetId(*resp.ID)

return resourceArmIotHubRead(d, meta)
}

Expand Down Expand Up @@ -393,6 +444,11 @@ func resourceArmIotHubRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("route", routes); err != nil {
return fmt.Errorf("Error setting `route` in IoTHub %q: %+v", name, err)
}

fallbackRoute := flattenIoTHubFallbackRoute(properties.Routing)
if err := d.Set("fallback_route", fallbackRoute); err != nil {
return fmt.Errorf("Error setting `fallbackRoute` in IoTHub %q: %+v", name, err)
}
}

d.Set("name", name)
Expand Down Expand Up @@ -479,18 +535,14 @@ func expandIoTHubRoutes(d *schema.ResourceData) *[]devices.RouteProperties {
condition := route["condition"].(string)

endpointNamesRaw := route["endpoint_names"].([]interface{})
endpointsNames := make([]string, 0)
for _, n := range endpointNamesRaw {
endpointsNames = append(endpointsNames, n.(string))
}

isEnabled := route["enabled"].(bool)

routeProperties = append(routeProperties, devices.RouteProperties{
Name: &name,
Source: source,
Condition: &condition,
EndpointNames: &endpointsNames,
EndpointNames: utils.ExpandStringArray(endpointNamesRaw),
IsEnabled: &isEnabled,
})
}
Expand Down Expand Up @@ -532,7 +584,7 @@ func expandIoTHubEndpoints(d *schema.ResourceData, subscriptionId string) (*devi
FileNameFormat: &fileNameFormat,
BatchFrequencyInSeconds: &batchFrequencyInSeconds,
MaxChunkSizeInBytes: &maxChunkSizeInBytes,
Encoding: &encoding,
Encoding: devices.Encoding(encoding),
}
storageContainerProperties = append(storageContainerProperties, storageContainer)

Expand Down Expand Up @@ -573,6 +625,26 @@ func expandIoTHubEndpoints(d *schema.ResourceData, subscriptionId string) (*devi
}, nil
}

func expandIoTHubFallbackRoute(d *schema.ResourceData) *devices.FallbackRouteProperties {
fallbackRouteList := d.Get("fallback_route").([]interface{})
if len(fallbackRouteList) == 0 {
return nil
}

fallbackRouteMap := fallbackRouteList[0].(map[string]interface{})

source := fallbackRouteMap["source"].(string)
condition := fallbackRouteMap["condition"].(string)
isEnabled := fallbackRouteMap["enabled"].(bool)

return &devices.FallbackRouteProperties{
Source: &source,
Condition: &condition,
EndpointNames: utils.ExpandStringArray(fallbackRouteMap["endpoint_names"].([]interface{})),
IsEnabled: &isEnabled,
}
}

func expandIoTHubSku(d *schema.ResourceData) *devices.IotHubSkuInfo {
skuList := d.Get("sku").([]interface{})
skuMap := skuList[0].(map[string]interface{})
Expand Down Expand Up @@ -654,9 +726,8 @@ func flattenIoTHubEndpoint(input *devices.RoutingProperties) []interface{} {
if chunkSize := container.MaxChunkSizeInBytes; chunkSize != nil {
output["max_chunk_size_in_bytes"] = *chunkSize
}
if encoding := container.Encoding; encoding != nil {
output["encoding"] = *encoding
}

output["encoding"] = string(container.Encoding)
output["type"] = "AzureIotHub.StorageContainer"

results = append(results, output)
Expand Down Expand Up @@ -740,6 +811,29 @@ func flattenIoTHubRoute(input *devices.RoutingProperties) []interface{} {
return results
}

func flattenIoTHubFallbackRoute(input *devices.RoutingProperties) []interface{} {
if input.FallbackRoute == nil {
return []interface{}{}
}

output := make(map[string]interface{})
route := input.FallbackRoute

if condition := route.Condition; condition != nil {
output["condition"] = *condition
}
if isEnabled := route.IsEnabled; isEnabled != nil {
output["enabled"] = *isEnabled
}
if source := route.Source; source != nil {
output["source"] = *source
}

output["endpoint_names"] = utils.FlattenStringArray(route.EndpointNames)

return []interface{}{output}
}

func validateIoTHubEndpointName(v interface{}, _ string) (warnings []string, errors []error) {
value := v.(string)

Expand Down
58 changes: 58 additions & 0 deletions azurerm/resource_arm_iothub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,33 @@ func TestAccAzureRMIotHub_customRoutes(t *testing.T) {
})
}

func TestAccAzureRMIotHub_fallbackRoute(t *testing.T) {
resourceName := "azurerm_iothub.test"
rInt := tf.AccRandTimeInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMIotHubDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMIotHub_fallbackRoute(rInt, testLocation()),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMIotHubExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "fallback_route.0.source", "DeviceMessages"),
resource.TestCheckResourceAttr(resourceName, "fallback_route.0.endpoint_names.#", "1"),
resource.TestCheckResourceAttr(resourceName, "fallback_route.0.enabled", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testCheckAzureRMIotHubDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*ArmClient).iothubResourceClient
ctx := testAccProvider.Meta().(*ArmClient).StopContext
Expand Down Expand Up @@ -298,3 +325,34 @@ resource "azurerm_iothub" "test" {
}
`, rInt, location, rStr, rInt)
}

func testAccAzureRMIotHub_fallbackRoute(rInt int, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_iothub" "test" {
name = "acctestIoTHub-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
sku {
name = "S1"
tier = "Standard"
capacity = "1"
}
fallback_route {
source = "DeviceMessages"
endpoint_names = ["events"]
enabled = true
}
tags {
"purpose" = "testing"
}
}
`, rInt, location, rInt)
}
Loading

0 comments on commit 9bd7bd8

Please sign in to comment.