Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_iothub - Add support for cloud_to_device block #14546

Merged
merged 2 commits into from
Dec 16, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions internal/services/iothub/iothub_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,55 @@ func resourceIotHub() *pluginsdk.Resource {
},
},

"cloud_to_device": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"max_delivery_count": {
Type: pluginsdk.TypeInt,
Optional: true,
Default: 10,
ValidateFunc: validation.IntBetween(1, 100),
},
"default_ttl": {
Type: pluginsdk.TypeString,
Optional: true,
Default: "PT1H",
ValidateFunc: validate.ISO8601DurationBetween("PT15M", "P2D"),
},
"feedback": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"time_to_live": {
Type: pluginsdk.TypeString,
Optional: true,
Default: "PT1H",
ValidateFunc: validate.ISO8601DurationBetween("PT15M", "P2D"),
},
"max_delivery_count": {
Type: pluginsdk.TypeInt,
Optional: true,
Default: 10,
ValidateFunc: validation.IntBetween(1, 100),
},
"lock_duration": {
Type: pluginsdk.TypeString,
Optional: true,
Default: "PT60S",
ValidateFunc: validate.ISO8601DurationBetween("PT5S", "PT300S"),
},
},
},
},
},
},
},

"min_tls_version": {
Type: pluginsdk.TypeString,
Optional: true,
Expand Down Expand Up @@ -548,6 +597,11 @@ func resourceIotHubCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) err
return fmt.Errorf("expanding `file_upload`: %+v", err)
}

cloudToDeviceProperties := &devices.CloudToDeviceProperties{}
if _, ok := d.GetOk("cloud_to_device"); ok {
cloudToDeviceProperties = expandIoTHubCloudToDevice(d)
}

props := devices.IotHubDescription{
Name: utils.String(id.Name),
Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))),
Expand All @@ -558,6 +612,7 @@ func resourceIotHubCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) err
StorageEndpoints: storageEndpoints,
MessagingEndpoints: messagingEndpoints,
EnableFileUploadNotifications: &enableFileUploadNotifications,
CloudToDevice: cloudToDeviceProperties,
},
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}
Expand Down Expand Up @@ -698,6 +753,11 @@ func resourceIotHubRead(d *pluginsdk.ResourceData, meta interface{}) error {
d.Set("public_network_access_enabled", enabled == devices.PublicNetworkAccessEnabled)
}

cloudToDevice := flattenIoTHubCloudToDevice(properties.CloudToDevice)
if err := d.Set("cloud_to_device", cloudToDevice); err != nil {
return fmt.Errorf("setting `cloudToDevice` in IoTHub %q: %+v", id.Name, err)
}

d.Set("min_tls_version", properties.MinTLSVersion)
}

Expand Down Expand Up @@ -993,6 +1053,36 @@ func expandIoTHubSku(d *pluginsdk.ResourceData) *devices.IotHubSkuInfo {
}
}

func expandIoTHubCloudToDevice(d *pluginsdk.ResourceData) *devices.CloudToDeviceProperties {
ctdList := d.Get("cloud_to_device").([]interface{})
if len(ctdList) == 0 {
return nil
}
cloudToDevice := devices.CloudToDeviceProperties{}
ctdMap := ctdList[0].(map[string]interface{})
defaultTimeToLive := ctdMap["default_ttl"].(string)

cloudToDevice.DefaultTTLAsIso8601 = &defaultTimeToLive
cloudToDevice.MaxDeliveryCount = utils.Int32(int32(ctdMap["max_delivery_count"].(int)))
feedback := ctdMap["feedback"].([]interface{})

cloudToDeviceFeedback := devices.FeedbackProperties{}
if len(feedback) > 0 {
feedbackMap := feedback[0].(map[string]interface{})

lockDuration := feedbackMap["lock_duration"].(string)
timeToLive := feedbackMap["time_to_live"].(string)

cloudToDeviceFeedback.TTLAsIso8601 = &timeToLive
cloudToDeviceFeedback.LockDurationAsIso8601 = &lockDuration
cloudToDeviceFeedback.MaxDeliveryCount = utils.Int32(int32(feedbackMap["max_delivery_count"].(int)))
}

cloudToDevice.Feedback = &cloudToDeviceFeedback

return &cloudToDevice
}

func flattenIoTHubSku(input *devices.IotHubSkuInfo) []interface{} {
output := make(map[string]interface{})

Expand Down Expand Up @@ -1244,6 +1334,44 @@ func flattenIoTHubFallbackRoute(input *devices.RoutingProperties) []interface{}
return []interface{}{output}
}

func flattenIoTHubCloudToDevice(input *devices.CloudToDeviceProperties) []interface{} {
if input == nil {
return []interface{}{}
}

output := make(map[string]interface{})

if maxDeliveryCount := input.MaxDeliveryCount; maxDeliveryCount != nil {
output["max_delivery_count"] = *maxDeliveryCount
}
if defaultTimeToLive := input.DefaultTTLAsIso8601; defaultTimeToLive != nil {
output["default_ttl"] = *defaultTimeToLive
}

output["feedback"] = flattenIoTHubCloudToDeviceFeedback(input.Feedback)

return []interface{}{output}
}

func flattenIoTHubCloudToDeviceFeedback(input *devices.FeedbackProperties) []interface{} {
if input == nil {
return []interface{}{}
}

feedback := make(map[string]interface{})
if feedbackMaxDeliveryCount := input.MaxDeliveryCount; feedbackMaxDeliveryCount != nil {
feedback["max_delivery_count"] = *feedbackMaxDeliveryCount
}
if feedbackTimeToLive := input.TTLAsIso8601; feedbackTimeToLive != nil {
feedback["time_to_live"] = *feedbackTimeToLive
}
if feedbackLockDuration := input.LockDurationAsIso8601; feedbackLockDuration != nil {
feedback["lock_duration"] = *feedbackLockDuration
}

return []interface{}{feedback}
}

func expandIPFilterRules(d *pluginsdk.ResourceData) *[]devices.IPFilterRule {
ipFilterRuleList := d.Get("ip_filter_rule").([]interface{})
if len(ipFilterRuleList) == 0 {
Expand Down
107 changes: 107 additions & 0 deletions internal/services/iothub/iothub_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,37 @@ func TestAccIotHub_minTLSVersion(t *testing.T) {
})
}

func TestAccIotHub_cloudToDevice(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_iothub", "test")
r := IotHubResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.cloudToDevice(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("cloud_to_device.0.max_delivery_count").HasValue("20"),
check.That(data.ResourceName).Key("cloud_to_device.0.default_ttl").HasValue("PT1H30M"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.time_to_live").HasValue("PT1H15M"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.max_delivery_count").HasValue("25"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.lock_duration").HasValue("PT55S"),
),
},
{
Config: r.cloudToDeviceUpdated(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("cloud_to_device.0.max_delivery_count").HasValue("30"),
check.That(data.ResourceName).Key("cloud_to_device.0.default_ttl").HasValue("PT1H"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.time_to_live").HasValue("PT1H10M"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.max_delivery_count").HasValue("15"),
check.That(data.ResourceName).Key("cloud_to_device.0.feedback.0.lock_duration").HasValue("PT30S"),
),
},
data.ImportStep(),
})
}

func (t IotHubResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := parse.IotHubID(state.ID)
if err != nil {
Expand Down Expand Up @@ -977,3 +1008,79 @@ resource "azurerm_iothub" "test" {
}
`, data.RandomInteger, "eastus", data.RandomInteger)
}

func (IotHubResource) cloudToDevice(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-iothub-%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 = "B1"
capacity = "1"
}

cloud_to_device {
max_delivery_count = 20
default_ttl = "PT1H30M"
feedback {
time_to_live = "PT1H15M"
max_delivery_count = 25
lock_duration = "PT55S"
}
}

tags = {
purpose = "testing"
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func (IotHubResource) cloudToDeviceUpdated(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-iothub-%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 = "B1"
capacity = "1"
}

cloud_to_device {
max_delivery_count = 30
default_ttl = "PT1H"
feedback {
time_to_live = "PT1H10M"
max_delivery_count = 15
lock_duration = "PT30S"
}
}

tags = {
purpose = "testing"
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}
32 changes: 32 additions & 0 deletions website/docs/r/iothub.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ resource "azurerm_iothub" "example" {
endpoint_names = ["export", "export2"]
}

cloud_to_device {
max_delivery_count = 30
default_ttl = "PT1H"
feedback {
time_to_live = "PT1H10M"
max_delivery_count = 15
lock_duration = "PT30S"
}
}

tags = {
purpose = "testing"
}
Expand Down Expand Up @@ -148,6 +158,8 @@ The following arguments are supported:

* `enrichment` - (Optional) A `enrichment` block as defined below.

* `cloud_to_device` - (Optional) A `cloud_to_device` block as defined below.

* `public_network_access_enabled` - (Optional) Is the IotHub resource accessible from a public network?

* `min_tls_version` - (Optional) Specifies the minimum TLS version to support for this hub. The only valid value is `1.2`. Changing this forces a new resource to be created.
Expand Down Expand Up @@ -250,6 +262,26 @@ A `file_upload` block supports the following:

* `max_delivery_count` - (Optional) The number of times the IoT hub attempts to deliver a file upload notification message. It evaluates to 10 by default.

---

A `cloud_to_device` block supports the following:

* `max_delivery_count` - (Optional) The maximum delivery count for cloud-to-device per-device queues. This value must be between 1 and 100, and evaluates to 10 by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should quote values

Suggested change
* `max_delivery_count` - (Optional) The maximum delivery count for cloud-to-device per-device queues. This value must be between 1 and 100, and evaluates to 10 by default.
* `max_delivery_count` - (Optional) The maximum delivery count for cloud-to-device per-device queues. This value must be between `1` and `100`, and evaluates to `10` by default.


* `default_ttl` - (Optional) The default time to live for cloud-to-device messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between 1 minute and 48 hours, and evaluates to 'PT1H' by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `default_ttl` - (Optional) The default time to live for cloud-to-device messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between 1 minute and 48 hours, and evaluates to 'PT1H' by default.
* `default_ttl` - (Optional) The default time to live for cloud-to-device messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between `1` minute and `48` hours, and evaluates to 'PT1H' by default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @katbyte I wasn't sure if I should highlight 1 and 48 here as they aren't actual possible values in this case?


* `feedback` - (Optional) A `feedback` block as defined below.

---

A `feedback` block supports the following:

* `time_to_live` - (Optional) The retention time for service-bound feedback messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between 1 minute and 48 hours, and evaluates to 'PT1H' by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `time_to_live` - (Optional) The retention time for service-bound feedback messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between 1 minute and 48 hours, and evaluates to 'PT1H' by default.
* `time_to_live` - (Optional) The retention time for service-bound feedback messages, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between `1` minute and `48` hours, and evaluates to 'PT1H' by default.


* `max_delivery_count` - (Optional) The maximum delivery count for the feedback queue. This value must be between 1 and 100, and evaluates to 10 by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `max_delivery_count` - (Optional) The maximum delivery count for the feedback queue. This value must be between 1 and 100, and evaluates to 10 by default.
* `max_delivery_count` - (Optional) The maximum delivery count for the feedback queue. This value must be between `1` and `100`, and evaluates to `10` by default.


* `lock_duration` - (Optional) The lock duration for the feedback queue, specified as an [ISO 8601 timespan duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). This value must be between 5 and 300 seconds, and evaluates to 'PT60S' by default.

## Attributes Reference

The following attributes are exported:
Expand Down