Skip to content

Commit

Permalink
New Resource: azurerm_iothub_route #4923
Browse files Browse the repository at this point in the history
  • Loading branch information
mbfrahry committed Nov 21, 2019
2 parents 7914184 + 09f6dd5 commit b7371f9
Show file tree
Hide file tree
Showing 10 changed files with 734 additions and 12 deletions.
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_iothub_dps_certificate": resourceArmIotHubDPSCertificate(),
"azurerm_iothub_consumer_group": resourceArmIotHubConsumerGroup(),
"azurerm_iothub": resourceArmIotHub(),
"azurerm_iothub_route": resourceArmIotHubRoute(),
"azurerm_iothub_endpoint_eventhub": resourceArmIotHubEndpointEventHub(),
"azurerm_iothub_endpoint_servicebus_queue": resourceArmIotHubEndpointServiceBusQueue(),
"azurerm_iothub_endpoint_servicebus_topic": resourceArmIotHubEndpointServiceBusTopic(),
Expand Down
10 changes: 6 additions & 4 deletions azurerm/resource_arm_iothub.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ func resourceArmIotHub() *schema.Resource {
"route": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Expand Down Expand Up @@ -470,11 +471,12 @@ func resourceArmIotHubCreateUpdate(d *schema.ResourceData, meta interface{}) err
skuInfo := expandIoTHubSku(d)
t := d.Get("tags").(map[string]interface{})

fallbackRoute := expandIoTHubFallbackRoute(d)
routes := expandIoTHubRoutes(d)
routingProperties := devices.RoutingProperties{
Routes: routes,
FallbackRoute: fallbackRoute,
FallbackRoute: expandIoTHubFallbackRoute(d),
}

if _, ok := d.GetOk("route"); ok {
routingProperties.Routes = expandIoTHubRoutes(d)
}

if _, ok := d.GetOk("endpoint"); ok {
Expand Down
4 changes: 2 additions & 2 deletions azurerm/resource_arm_iothub_endpoint_eventhub.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ func resourceArmIotHubEndpointEventHubCreateUpdate(d *schema.ResourceData, meta
}
endpoints = append(endpoints, eventhubEndpoint)
alreadyExists = true
} else {
endpoints = append(endpoints, existingEndpoint)
}
} else {
endpoints = append(endpoints, existingEndpoint)
}
}

Expand Down
4 changes: 2 additions & 2 deletions azurerm/resource_arm_iothub_endpoint_servicebus_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ func resourceArmIotHubEndpointServiceBusQueueCreateUpdate(d *schema.ResourceData
}
endpoints = append(endpoints, queueEndpoint)
alreadyExists = true
} else {
endpoints = append(endpoints, existingEndpoint)
}
} else {
endpoints = append(endpoints, existingEndpoint)
}
}

Expand Down
4 changes: 2 additions & 2 deletions azurerm/resource_arm_iothub_endpoint_servicebus_topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ func resourceArmIotHubEndpointServiceBusTopicCreateUpdate(d *schema.ResourceData
}
endpoints = append(endpoints, topicEndpoint)
alreadyExists = true
} else {
endpoints = append(endpoints, existingEndpoint)
}
} else {
endpoints = append(endpoints, existingEndpoint)
}
}

Expand Down
4 changes: 2 additions & 2 deletions azurerm/resource_arm_iothub_endpoint_storage_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ func resourceArmIotHubEndpointStorageContainerCreateUpdate(d *schema.ResourceDat
}
endpoints = append(endpoints, storageContainerEndpoint)
alreadyExists = true
} else {
endpoints = append(endpoints, existingEndpoint)
}
} else {
endpoints = append(endpoints, existingEndpoint)
}
}

Expand Down
268 changes: 268 additions & 0 deletions azurerm/resource_arm_iothub_route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
package azurerm

import (
"fmt"
"regexp"
"strings"

"github.com/Azure/azure-sdk-for-go/services/preview/iothub/mgmt/2018-12-01-preview/devices"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"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/locks"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmIotHubRoute() *schema.Resource {
return &schema.Resource{
Create: resourceArmIotHubRouteCreateUpdate,
Read: resourceArmIotHubRouteRead,
Update: resourceArmIotHubRouteCreateUpdate,
Delete: resourceArmIotHubRouteDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
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.",
),
},

"resource_group_name": azure.SchemaResourceGroupName(),

"iothub_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.IoTHubName,
},

"source": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(devices.RoutingSourceDeviceJobLifecycleEvents),
string(devices.RoutingSourceDeviceLifecycleEvents),
string(devices.RoutingSourceDeviceMessages),
string(devices.RoutingSourceInvalid),
string(devices.RoutingSourceTwinChangeEvents),
}, 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,
// Currently only one endpoint is allowed. With that comment from Microsoft, we'll leave this open to enhancement when they add multiple endpoint support.
MaxItems: 1,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
Required: true,
},
"enabled": {
Type: schema.TypeBool,
Required: true,
},
},
}
}

func resourceArmIotHubRouteCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).IoTHub.ResourceClient
ctx := meta.(*ArmClient).StopContext

iothubName := d.Get("iothub_name").(string)
resourceGroup := d.Get("resource_group_name").(string)

locks.ByName(iothubName, iothubResourceName)
defer locks.UnlockByName(iothubName, iothubResourceName)

iothub, err := client.Get(ctx, resourceGroup, iothubName)
if err != nil {
if utils.ResponseWasNotFound(iothub.Response) {
return fmt.Errorf("IotHub %q (Resource Group %q) was not found", iothubName, resourceGroup)
}

return fmt.Errorf("Error loading IotHub %q (Resource Group %q): %+v", iothubName, resourceGroup, err)
}

routeName := d.Get("name").(string)

resourceId := fmt.Sprintf("%s/Routes/%s", *iothub.ID, routeName)

source := devices.RoutingSource(d.Get("source").(string))
condition := d.Get("condition").(string)
endpointNamesRaw := d.Get("endpoint_names").([]interface{})
isEnabled := d.Get("enabled").(bool)

route := devices.RouteProperties{
Name: &routeName,
Source: source,
Condition: &condition,
EndpointNames: utils.ExpandStringSlice(endpointNamesRaw),
IsEnabled: &isEnabled,
}

routing := iothub.Properties.Routing

if routing == nil {
routing = &devices.RoutingProperties{}
}

if routing.Routes == nil {
routes := make([]devices.RouteProperties, 0)
routing.Routes = &routes
}

routes := make([]devices.RouteProperties, 0)

alreadyExists := false
for _, existingRoute := range *routing.Routes {
if existingRoute.Name != nil {
if strings.EqualFold(*existingRoute.Name, routeName) {
if d.IsNewResource() && requireResourcesToBeImported {
return tf.ImportAsExistsError("azurerm_iothub_route", resourceId)
}
routes = append(routes, route)
alreadyExists = true
} else {
routes = append(routes, existingRoute)
}
}
}

if d.IsNewResource() {
routes = append(routes, route)
} else if !alreadyExists {
return fmt.Errorf("Unable to find Route %q defined for IotHub %q (Resource Group %q)", routeName, iothubName, resourceGroup)
}

routing.Routes = &routes

future, err := client.CreateOrUpdate(ctx, resourceGroup, iothubName, iothub, "")
if err != nil {
return fmt.Errorf("Error creating/updating IotHub %q (Resource Group %q): %+v", iothubName, resourceGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for the completion of the creating/updating of IotHub %q (Resource Group %q): %+v", iothubName, resourceGroup, err)
}

d.SetId(resourceId)

return resourceArmIotHubRouteRead(d, meta)
}

func resourceArmIotHubRouteRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).IoTHub.ResourceClient
ctx := meta.(*ArmClient).StopContext

parsedIothubRouteId, err := parseAzureResourceID(d.Id())

if err != nil {
return err
}

resourceGroup := parsedIothubRouteId.ResourceGroup
iothubName := parsedIothubRouteId.Path["IotHubs"]
routeName := parsedIothubRouteId.Path["Routes"]

iothub, err := client.Get(ctx, resourceGroup, iothubName)
if err != nil {
return fmt.Errorf("Error loading IotHub %q (Resource Group %q): %+v", iothubName, resourceGroup, err)
}

d.Set("name", routeName)
d.Set("iothub_name", iothubName)
d.Set("resource_group_name", resourceGroup)

if iothub.Properties == nil || iothub.Properties.Routing == nil {
return nil
}

if routes := iothub.Properties.Routing.Routes; routes != nil {
for _, route := range *routes {
if route.Name != nil {
if strings.EqualFold(*route.Name, routeName) {
d.Set("source", route.Source)
d.Set("condition", route.Condition)
d.Set("enabled", route.IsEnabled)
d.Set("endpoint_names", route.EndpointNames)
}
}
}
}

return nil
}

func resourceArmIotHubRouteDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).IoTHub.ResourceClient
ctx := meta.(*ArmClient).StopContext

parsedIothubRouteId, err := parseAzureResourceID(d.Id())

if err != nil {
return err
}

resourceGroup := parsedIothubRouteId.ResourceGroup
iothubName := parsedIothubRouteId.Path["IotHubs"]
routeName := parsedIothubRouteId.Path["Routes"]

locks.ByName(iothubName, iothubResourceName)
defer locks.UnlockByName(iothubName, iothubResourceName)

iothub, err := client.Get(ctx, resourceGroup, iothubName)
if err != nil {
if utils.ResponseWasNotFound(iothub.Response) {
return fmt.Errorf("IotHub %q (Resource Group %q) was not found", iothubName, resourceGroup)
}

return fmt.Errorf("Error loading IotHub %q (Resource Group %q): %+v", iothubName, resourceGroup, err)
}

if iothub.Properties == nil || iothub.Properties.Routing == nil {
return nil
}
routes := iothub.Properties.Routing.Routes

if routes == nil {
return nil
}

updatedRoutes := make([]devices.RouteProperties, 0)
for _, route := range *routes {
if route.Name != nil {
if !strings.EqualFold(*route.Name, routeName) {
updatedRoutes = append(updatedRoutes, route)
}
}
}

iothub.Properties.Routing.Routes = &updatedRoutes

future, err := client.CreateOrUpdate(ctx, resourceGroup, iothubName, iothub, "")
if err != nil {
return fmt.Errorf("Error updating IotHub %q (Resource Group %q) with Route %q: %+v", iothubName, resourceGroup, routeName, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for IotHub %q (Resource Group %q) to finish updating Route %q: %+v", iothubName, resourceGroup, routeName, err)
}

return nil
}
Loading

0 comments on commit b7371f9

Please sign in to comment.