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 - support for new property endpoint.subscription_id #27524

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type IotHubEndpointCosmosDBAccountModel struct {
PartitionKeyTemplate string `tfschema:"partition_key_template"`
PrimaryKey string `tfschema:"primary_key"`
SecondaryKey string `tfschema:"secondary_key"`
SubscriptionId string `tfschema:"subscription_id"`
}

func (r IotHubEndpointCosmosDBAccountResource) Arguments() map[string]*pluginsdk.Schema {
Expand Down Expand Up @@ -131,6 +132,14 @@ func (r IotHubEndpointCosmosDBAccountResource) Arguments() map[string]*pluginsdk
ConflictsWith: []string{"identity_id"},
RequiredWith: []string{"primary_key"},
},

// NOTE: O+C : required since this property would always be set even if it isn't specified in the tf config, otherwise it would cause a diff and break existing users
"subscription_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsUUID,
},
}
}

Expand Down Expand Up @@ -183,14 +192,22 @@ func (r IotHubEndpointCosmosDBAccountResource) Create() sdk.ResourceFunc {
authenticationType := devices.AuthenticationType(state.AuthenticationType)
cosmosDBAccountEndpoint := devices.RoutingCosmosDBSQLAPIProperties{
Name: pointer.To(id.EndpointName),
SubscriptionID: pointer.To(subscriptionId),
ResourceGroup: pointer.To(state.ResourceGroupName),
AuthenticationType: authenticationType,
CollectionName: pointer.To(state.ContainerName),
DatabaseName: pointer.To(state.DatabaseName),
EndpointURI: pointer.To(state.EndpointUri),
}

// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := metadata.ResourceData.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
cosmosDBAccountEndpoint.SubscriptionID = pointer.To(subscriptionId)
} else {
cosmosDBAccountEndpoint.SubscriptionID = pointer.To(state.SubscriptionId)
}

if state.PartitionKeyName != "" {
cosmosDBAccountEndpoint.PartitionKeyName = pointer.To(state.PartitionKeyName)
}
Expand Down Expand Up @@ -298,6 +315,7 @@ func (r IotHubEndpointCosmosDBAccountResource) Read() sdk.ResourceFunc {
PartitionKeyTemplate: pointer.From(endpoint.PartitionKeyTemplate),
PrimaryKey: oldState.PrimaryKey,
SecondaryKey: oldState.SecondaryKey,
SubscriptionId: pointer.From(endpoint.SubscriptionID),
}

authenticationType := string(devices.AuthenticationTypeKeyBased)
Expand Down Expand Up @@ -326,6 +344,7 @@ func (r IotHubEndpointCosmosDBAccountResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTHub.ResourceClient
subscriptionId := metadata.Client.Account.SubscriptionId

id, err := parse.EndpointCosmosDBAccountID(metadata.ResourceData.Id())
if err != nil {
Expand Down Expand Up @@ -401,6 +420,16 @@ func (r IotHubEndpointCosmosDBAccountResource) Update() sdk.ResourceFunc {
}
}

// As `subscription_id` is `O+C`, `HasChange()` can't detect the change when it isn't specified. And `subscription_id` always needs to be set to the subscription ID used in the provider block when it isn't specified. So, `HasChange()` is not needed.
// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := metadata.ResourceData.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
endpoint.SubscriptionID = pointer.To(subscriptionId)
} else {
endpoint.SubscriptionID = pointer.To(state.SubscriptionId)
}

(*iothub.Properties.Routing.Endpoints.CosmosDBSQLCollections)[i] = endpoint

future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.IotHubName, iothub, "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ resource "azurerm_iothub_endpoint_cosmosdb_account" "test" {
endpoint_uri = azurerm_cosmosdb_account.test.endpoint
primary_key = azurerm_cosmosdb_account.test.primary_key
secondary_key = azurerm_cosmosdb_account.test.secondary_key
subscription_id = data.azurerm_client_config.current.subscription_id

partition_key_name = "%s"
partition_key_template = "%s"
Expand Down Expand Up @@ -376,6 +377,8 @@ provider "azurerm" {
features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "iothub" {
name = "acctestRG-iothub-%[2]d"
location = "%[1]s"
Expand Down
20 changes: 19 additions & 1 deletion internal/services/iothub/iothub_endpoint_eventhub_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
Expand Down Expand Up @@ -119,6 +120,14 @@ func resourceIothubEndpointEventHubSchema() map[string]*pluginsdk.Schema {
ConflictsWith: []string{"identity_id"},
ExactlyOneOf: []string{"endpoint_uri", "connection_string"},
},

// NOTE: O+C : required since this property would always be set even if it isn't specified in the tf config, otherwise it would cause a diff and break existing users
"subscription_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsUUID,
},
}
}

Expand Down Expand Up @@ -156,10 +165,18 @@ func resourceIotHubEndpointEventHubCreateUpdate(d *pluginsdk.ResourceData, meta
eventhubEndpoint := devices.RoutingEventHubProperties{
AuthenticationType: authenticationType,
Name: utils.String(id.EndpointName),
SubscriptionID: utils.String(meta.(*clients.Client).Account.SubscriptionId),
ResourceGroup: utils.String(endpointRG),
}

// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := d.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
eventhubEndpoint.SubscriptionID = pointer.To(meta.(*clients.Client).Account.SubscriptionId)
} else {
eventhubEndpoint.SubscriptionID = pointer.To(d.Get("subscription_id").(string))
}

if authenticationType == devices.AuthenticationTypeKeyBased {
if v, ok := d.GetOk("connection_string"); ok {
eventhubEndpoint.ConnectionString = utils.String(v.(string))
Expand Down Expand Up @@ -268,6 +285,7 @@ func resourceIotHubEndpointEventHubRead(d *pluginsdk.ResourceData, meta interfac
if strings.EqualFold(*existingEndpointName, id.EndpointName) {
exist = true
d.Set("resource_group_name", endpoint.ResourceGroup)
d.Set("subscription_id", pointer.From(endpoint.SubscriptionID))

authenticationType := string(devices.AuthenticationTypeKeyBased)
if string(endpoint.AuthenticationType) != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ provider "azurerm" {
features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-eventhub-%[1]d"
location = "%[2]s"
Expand Down Expand Up @@ -278,6 +280,7 @@ resource "azurerm_iothub_endpoint_eventhub" "test" {
resource_group_name = azurerm_resource_group.test.name
name = "acctest"
iothub_id = azurerm_iothub.test.id
subscription_id = data.azurerm_client_config.current.subscription_id

connection_string = azurerm_eventhub_authorization_rule.test.primary_connection_string
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
Expand Down Expand Up @@ -119,6 +120,14 @@ func resourceIothubEndpointServicebusQueue() map[string]*pluginsdk.Schema {
ConflictsWith: []string{"identity_id"},
ExactlyOneOf: []string{"endpoint_uri", "connection_string"},
},

// NOTE: O+C : required since this property would always be set even if it isn't specified in the tf config, otherwise it would cause a diff and break existing users
"subscription_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsUUID,
},
}

return out
Expand Down Expand Up @@ -159,10 +168,18 @@ func resourceIotHubEndpointServiceBusQueueCreateUpdate(d *pluginsdk.ResourceData
queueEndpoint := devices.RoutingServiceBusQueueEndpointProperties{
AuthenticationType: authenticationType,
Name: utils.String(id.EndpointName),
SubscriptionID: utils.String(subscriptionID),
ResourceGroup: utils.String(endpointRG),
}

// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := d.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
queueEndpoint.SubscriptionID = pointer.To(subscriptionID)
} else {
queueEndpoint.SubscriptionID = pointer.To(d.Get("subscription_id").(string))
}

if authenticationType == devices.AuthenticationTypeKeyBased {
if v, ok := d.GetOk("connection_string"); ok {
queueEndpoint.ConnectionString = utils.String(v.(string))
Expand Down Expand Up @@ -272,6 +289,7 @@ func resourceIotHubEndpointServiceBusQueueRead(d *pluginsdk.ResourceData, meta i
if strings.EqualFold(*existingEndpointName, id.EndpointName) {
exist = true
d.Set("resource_group_name", endpoint.ResourceGroup)
d.Set("subscription_id", pointer.From(endpoint.SubscriptionID))

authenticationType := string(devices.AuthenticationTypeKeyBased)
if string(endpoint.AuthenticationType) != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ provider "azurerm" {
features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-eventhub-%[1]d"
location = "%[2]s"
Expand Down Expand Up @@ -272,6 +274,7 @@ resource "azurerm_iothub_endpoint_servicebus_queue" "test" {
resource_group_name = azurerm_resource_group.test.name
name = "acctest"
iothub_id = azurerm_iothub.test.id
subscription_id = data.azurerm_client_config.current.subscription_id

connection_string = azurerm_servicebus_queue_authorization_rule.test.primary_connection_string
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
Expand Down Expand Up @@ -119,6 +120,14 @@ func resourceIothubEndpointServicebusTopicSchema() map[string]*pluginsdk.Schema
ConflictsWith: []string{"identity_id"},
ExactlyOneOf: []string{"endpoint_uri", "connection_string"},
},

// NOTE: O+C : required since this property would always be set even if it isn't specified in the tf config, otherwise it would cause a diff and break existing users
"subscription_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsUUID,
},
}
}

Expand Down Expand Up @@ -157,10 +166,18 @@ func resourceIotHubEndpointServiceBusTopicCreateUpdate(d *pluginsdk.ResourceData
topicEndpoint := devices.RoutingServiceBusTopicEndpointProperties{
AuthenticationType: authenticationType,
Name: utils.String(id.EndpointName),
SubscriptionID: utils.String(subscriptionID),
ResourceGroup: utils.String(endpointRG),
}

// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := d.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
topicEndpoint.SubscriptionID = pointer.To(subscriptionID)
} else {
topicEndpoint.SubscriptionID = pointer.To(d.Get("subscription_id").(string))
}

if authenticationType == devices.AuthenticationTypeKeyBased {
if v, ok := d.GetOk("connection_string"); ok {
topicEndpoint.ConnectionString = utils.String(v.(string))
Expand Down Expand Up @@ -270,6 +287,7 @@ func resourceIotHubEndpointServiceBusTopicRead(d *pluginsdk.ResourceData, meta i
if strings.EqualFold(*existingEndpointName, id.EndpointName) {
exist = true
d.Set("resource_group_name", endpoint.ResourceGroup)
d.Set("subscription_id", pointer.From(endpoint.SubscriptionID))

authenticationType := string(devices.AuthenticationTypeKeyBased)
if string(endpoint.AuthenticationType) != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ provider "azurerm" {
features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-eventhub-%[1]d"
location = "%[2]s"
Expand Down Expand Up @@ -268,6 +270,7 @@ resource "azurerm_iothub_endpoint_servicebus_topic" "test" {
resource_group_name = azurerm_resource_group.test.name
name = "acctest"
iothub_id = azurerm_iothub.test.id
subscription_id = data.azurerm_client_config.current.subscription_id

connection_string = azurerm_servicebus_topic_authorization_rule.test.primary_connection_string
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
Expand Down Expand Up @@ -150,6 +151,14 @@ func resourceIothubEndpointStorageContainerSchema() map[string]*pluginsdk.Schema
string(devices.EncodingJSON),
}, true),
},

// NOTE: O+C : required since this property would always be set even if it isn't specified in the tf config, otherwise it would cause a diff and break existing users
"subscription_id": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsUUID,
},
}
}

Expand Down Expand Up @@ -193,7 +202,6 @@ func resourceIotHubEndpointStorageContainerCreateUpdate(d *pluginsdk.ResourceDat
storageContainerEndpoint := devices.RoutingStorageContainerProperties{
AuthenticationType: authenticationType,
Name: &id.EndpointName,
SubscriptionID: &subscriptionID,
ResourceGroup: &endpointRG,
ContainerName: &containerName,
FileNameFormat: &fileNameFormat,
Expand All @@ -202,6 +210,15 @@ func resourceIotHubEndpointStorageContainerCreateUpdate(d *pluginsdk.ResourceDat
Encoding: devices.Encoding(encoding),
}

// To align with the previous TF behavior, `subscription_id` needs to be set with the provider's subscription Id when it isn't specified in the tf config, otherwise TF behavior is different than before and it may block the existing users
// From the business perspective, the raw config handling is only deant for the case that the user has an CosmosDB Account whose Endpoint's subscription is not the provider's one. Then the user wants to reset it to the provider's one by unset the subscription_id
// From the TF code perspective, given `Computed: true` is enabled, TF would always get the value from the last apply when this property isn't set in the tf config. So `d.GetRawConfig()` is required to determine if it's set in the tf config
if v := d.GetRawConfig().AsValueMap()["subscription_id"]; v.IsNull() {
storageContainerEndpoint.SubscriptionID = pointer.To(subscriptionID)
} else {
storageContainerEndpoint.SubscriptionID = pointer.To(d.Get("subscription_id").(string))
}

if authenticationType == devices.AuthenticationTypeKeyBased {
if v, ok := d.GetOk("connection_string"); ok {
storageContainerEndpoint.ConnectionString = utils.String(v.(string))
Expand Down Expand Up @@ -317,6 +334,7 @@ func resourceIotHubEndpointStorageContainerRead(d *pluginsdk.ResourceData, meta
d.Set("max_chunk_size_in_bytes", endpoint.MaxChunkSizeInBytes)
d.Set("encoding", endpoint.Encoding)
d.Set("resource_group_name", endpoint.ResourceGroup)
d.Set("subscription_id", pointer.From(endpoint.SubscriptionID))

authenticationType := string(devices.AuthenticationTypeKeyBased)
if string(endpoint.AuthenticationType) != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ provider "azurerm" {
features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-iothub-%[1]d"
location = "%[2]s"
Expand Down Expand Up @@ -263,6 +265,7 @@ resource "azurerm_iothub_endpoint_storage_container" "test" {
batch_frequency_in_seconds = 60
max_chunk_size_in_bytes = 10485760
encoding = "JSON"
subscription_id = data.azurerm_client_config.current.subscription_id
}
`, data.RandomInteger, data.Locations.Primary)
}
Expand Down
Loading
Loading