Skip to content

Commit

Permalink
r\iothub: Add support for identity-based file_upload (#15874)
Browse files Browse the repository at this point in the history
  • Loading branch information
myc2h6o authored Mar 18, 2022
1 parent fb03eb0 commit a9488d4
Show file tree
Hide file tree
Showing 3 changed files with 306 additions and 10 deletions.
50 changes: 44 additions & 6 deletions internal/services/iothub/iothub_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,20 @@ func resourceIotHub() *pluginsdk.Resource {
Type: pluginsdk.TypeString,
Required: true,
},
"authentication_type": {
Type: pluginsdk.TypeString,
Optional: true,
Default: string(devices.AuthenticationTypeKeyBased),
ValidateFunc: validation.StringInSlice([]string{
string(devices.AuthenticationTypeKeyBased),
string(devices.AuthenticationTypeIdentityBased),
}, false),
},
"identity_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: msivalidate.UserAssignedIdentityID,
},
"notifications": {
Type: pluginsdk.TypeBool,
Optional: true,
Expand Down Expand Up @@ -717,7 +731,7 @@ func resourceIotHubCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) err
}
}

storageEndpoints, messagingEndpoints, enableFileUploadNotifications := expandIoTHubFileUpload(d)
storageEndpoints, messagingEndpoints, enableFileUploadNotifications, err := expandIoTHubFileUpload(d)
if err != nil {
return fmt.Errorf("expanding `file_upload`: %+v", err)
}
Expand Down Expand Up @@ -1002,7 +1016,7 @@ func expandIoTHubEnrichments(d *pluginsdk.ResourceData) *[]devices.EnrichmentPro
return &enrichmentProperties
}

func expandIoTHubFileUpload(d *pluginsdk.ResourceData) (map[string]*devices.StorageEndpointProperties, map[string]*devices.MessagingEndpointProperties, bool) {
func expandIoTHubFileUpload(d *pluginsdk.ResourceData) (map[string]*devices.StorageEndpointProperties, map[string]*devices.MessagingEndpointProperties, bool, error) {
fileUploadList := d.Get("file_upload").([]interface{})

storageEndpointProperties := make(map[string]*devices.StorageEndpointProperties)
Expand All @@ -1012,6 +1026,8 @@ func expandIoTHubFileUpload(d *pluginsdk.ResourceData) (map[string]*devices.Stor
if len(fileUploadList) > 0 {
fileUploadMap := fileUploadList[0].(map[string]interface{})

authenticationType := devices.AuthenticationType(fileUploadMap["authentication_type"].(string))
identityId := fileUploadMap["identity_id"].(string)
connectionStr := fileUploadMap["connection_string"].(string)
containerName := fileUploadMap["container_name"].(string)
notifications = fileUploadMap["notifications"].(bool)
Expand All @@ -1021,9 +1037,19 @@ func expandIoTHubFileUpload(d *pluginsdk.ResourceData) (map[string]*devices.Stor
lockDuration := fileUploadMap["lock_duration"].(string)

storageEndpointProperties["$default"] = &devices.StorageEndpointProperties{
SasTTLAsIso8601: &sasTTL,
ConnectionString: &connectionStr,
ContainerName: &containerName,
SasTTLAsIso8601: &sasTTL,
AuthenticationType: authenticationType,
ConnectionString: &connectionStr,
ContainerName: &containerName,
}

if identityId != "" {
if authenticationType != devices.AuthenticationTypeIdentityBased {
return nil, nil, false, fmt.Errorf("`identity_id` can only be specified when `authentication_type` is `identityBased`")
}
storageEndpointProperties["$default"].Identity = &devices.ManagedIdentity{
UserAssignedIdentity: &identityId,
}
}

messagingEndpointProperties["fileNotifications"] = &devices.MessagingEndpointProperties{
Expand All @@ -1033,7 +1059,7 @@ func expandIoTHubFileUpload(d *pluginsdk.ResourceData) (map[string]*devices.Stor
}
}

return storageEndpointProperties, messagingEndpointProperties, notifications
return storageEndpointProperties, messagingEndpointProperties, notifications, nil
}

func expandIoTHubEndpoints(d *pluginsdk.ResourceData, subscriptionId string) (*devices.RoutingEndpoints, error) {
Expand Down Expand Up @@ -1283,6 +1309,18 @@ func flattenIoTHubFileUpload(storageEndpoints map[string]*devices.StorageEndpoin
output["sas_ttl"] = *sasTTLAsIso8601
}

authenticationType := string(devices.AuthenticationTypeKeyBased)
if v := string(storageEndpointProperties.AuthenticationType); v != "" {
authenticationType = v
}
output["authentication_type"] = authenticationType

identityId := ""
if storageEndpointProperties.Identity != nil && storageEndpointProperties.Identity.UserAssignedIdentity != nil {
identityId = *storageEndpointProperties.Identity.UserAssignedIdentity
}
output["identity_id"] = identityId

if messagingEndpointProperties, ok := messagingEndpoints["fileNotifications"]; ok {
if lockDurationAsIso8601 := messagingEndpointProperties.LockDurationAsIso8601; lockDurationAsIso8601 != nil {
output["lock_duration"] = *lockDurationAsIso8601
Expand Down
258 changes: 254 additions & 4 deletions internal/services/iothub/iothub_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,14 @@ func TestAccIotHub_fileUpload(t *testing.T) {

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.fileUpload(data),
Config: r.fileUploadBasic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.fileUploadUpdate(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("file_upload.#").HasValue("1"),
Expand All @@ -189,6 +196,57 @@ func TestAccIotHub_fileUpload(t *testing.T) {
})
}

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

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.fileUploadAuthenticationTypeUserAssignedIdentity(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

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

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.fileUploadAuthenticationTypeDefault(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.fileUploadAuthenticationTypeUserAssignedIdentity(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.fileUploadAuthenticationTypeSystemAssignedIdentity(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.fileUploadAuthenticationTypeDefault(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccIotHub_withDifferentEndpointResourceGroup(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_iothub", "test")
r := IotHubResource{}
Expand Down Expand Up @@ -399,7 +457,7 @@ func TestAccIotHub_identityUpdate(t *testing.T) {
})
}

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

Expand All @@ -414,7 +472,7 @@ func TestAccIotHub_AuthenticationTypeUserAssignedIdentity(t *testing.T) {
})
}

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

Expand Down Expand Up @@ -1057,7 +1115,50 @@ resource "azurerm_iothub" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func (IotHubResource) fileUpload(data acceptance.TestData) string {
func (IotHubResource) fileUploadBasic(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_storage_account" "test" {
name = "acctestsa%s"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "test" {
name = "test"
storage_account_name = azurerm_storage_account.test.name
container_access_type = "private"
}
resource "azurerm_iothub" "test" {
name = "acctestIoTHub-%d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
sku {
name = "S1"
capacity = "1"
}
file_upload {
connection_string = azurerm_storage_account.test.primary_blob_connection_string
container_name = azurerm_storage_container.test.name
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger)
}

func (IotHubResource) fileUploadUpdate(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
Expand Down Expand Up @@ -1105,6 +1206,155 @@ resource "azurerm_iothub" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger)
}

func (r IotHubResource) fileUploadAuthenticationTypeDefault(data acceptance.TestData) string {
return fmt.Sprintf(`
%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"
capacity = "1"
}
file_upload {
connection_string = azurerm_storage_account.test.primary_blob_connection_string
container_name = azurerm_storage_container.test.name
}
identity {
type = "SystemAssigned, UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id,
]
}
depends_on = [
azurerm_role_assignment.test_storage_blob_data_contrib_user,
]
}
`, r.fileUploadAuthenticationTypeTemplate(data), data.RandomInteger)
}

func (r IotHubResource) fileUploadAuthenticationTypeSystemAssignedIdentity(data acceptance.TestData) string {
return fmt.Sprintf(`
%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"
capacity = "1"
}
file_upload {
connection_string = azurerm_storage_account.test.primary_blob_connection_string
container_name = azurerm_storage_container.test.name
authentication_type = "identityBased"
}
identity {
type = "SystemAssigned, UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id,
]
}
depends_on = [
azurerm_role_assignment.test_storage_blob_data_contrib_user,
]
}
`, r.fileUploadAuthenticationTypeTemplate(data), data.RandomInteger)
}

func (r IotHubResource) fileUploadAuthenticationTypeUserAssignedIdentity(data acceptance.TestData) string {
return fmt.Sprintf(`
%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"
capacity = "1"
}
file_upload {
connection_string = azurerm_storage_account.test.primary_blob_connection_string
container_name = azurerm_storage_container.test.name
authentication_type = "identityBased"
identity_id = azurerm_user_assigned_identity.test.id
}
identity {
type = "SystemAssigned, UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id,
]
}
depends_on = [
azurerm_role_assignment.test_storage_blob_data_contrib_user,
]
}
`, r.fileUploadAuthenticationTypeTemplate(data), data.RandomInteger)
}

func (IotHubResource) fileUploadAuthenticationTypeTemplate(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_storage_account" "test" {
name = "acctestsa%s"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "test" {
name = "test"
storage_account_name = azurerm_storage_account.test.name
container_access_type = "private"
}
resource "azurerm_user_assigned_identity" "test" {
name = "acctestuai-%d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
}
resource "azurerm_role_assignment" "test_storage_blob_data_contrib_user" {
role_definition_name = "Storage Blob Data Contributor"
scope = azurerm_storage_account.test.id
principal_id = azurerm_user_assigned_identity.test.principal_id
}
resource "azurerm_role_assignment" "test_storage_blob_data_contrib_system" {
role_definition_name = "Storage Blob Data Contributor"
scope = azurerm_storage_account.test.id
principal_id = azurerm_iothub.test.identity[0].principal_id
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger)
}

func (IotHubResource) publicAccessEnabled(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
Loading

0 comments on commit a9488d4

Please sign in to comment.