diff --git a/internal/services/iothub/iothub_certificate_resource.go b/internal/services/iothub/iothub_certificate_resource.go index 2d26bb08d6e9..847464875278 100644 --- a/internal/services/iothub/iothub_certificate_resource.go +++ b/internal/services/iothub/iothub_certificate_resource.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -23,6 +24,11 @@ func resourceIotHubCertificate() *pluginsdk.Resource { Update: resourceIotHubCertificateCreateUpdate, Delete: resourceIotHubCertificateDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubCertificateV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.IotHubCertificateID(id) return err diff --git a/internal/services/iothub/iothub_consumer_group_resource.go b/internal/services/iothub/iothub_consumer_group_resource.go index 483e59213434..daf7a50f5af8 100644 --- a/internal/services/iothub/iothub_consumer_group_resource.go +++ b/internal/services/iothub/iothub_consumer_group_resource.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -23,6 +24,11 @@ func resourceIotHubConsumerGroup() *pluginsdk.Resource { Read: resourceIotHubConsumerGroupRead, Delete: resourceIotHubConsumerGroupDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubConsumerGroupV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.ConsumerGroupID(id) return err diff --git a/internal/services/iothub/iothub_endpoint_eventhub_resource.go b/internal/services/iothub/iothub_endpoint_eventhub_resource.go index a9a226fa7eac..a56ee5e70c10 100644 --- a/internal/services/iothub/iothub_endpoint_eventhub_resource.go +++ b/internal/services/iothub/iothub_endpoint_eventhub_resource.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" iothubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -28,6 +29,11 @@ func resourceIotHubEndpointEventHub() *pluginsdk.Resource { Update: resourceIotHubEndpointEventHubCreateUpdate, Delete: resourceIotHubEndpointEventHubDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubEndPointEventHubV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.EndpointEventhubID(id) return err diff --git a/internal/services/iothub/iothub_endpoint_servicebus_queue_resource.go b/internal/services/iothub/iothub_endpoint_servicebus_queue_resource.go index 34b4e55c5595..238d1d9c09c4 100644 --- a/internal/services/iothub/iothub_endpoint_servicebus_queue_resource.go +++ b/internal/services/iothub/iothub_endpoint_servicebus_queue_resource.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" iothubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicebus/validate" @@ -28,6 +29,11 @@ func resourceIotHubEndpointServiceBusQueue() *pluginsdk.Resource { Update: resourceIotHubEndpointServiceBusQueueCreateUpdate, Delete: resourceIotHubEndpointServiceBusQueueDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubServiceBusQueueV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.EndpointServiceBusQueueID(id) return err diff --git a/internal/services/iothub/iothub_endpoint_servicebus_topic_resource.go b/internal/services/iothub/iothub_endpoint_servicebus_topic_resource.go index cf44fdfb34e8..c6a938f6eaf2 100644 --- a/internal/services/iothub/iothub_endpoint_servicebus_topic_resource.go +++ b/internal/services/iothub/iothub_endpoint_servicebus_topic_resource.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" iothubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicebus/validate" @@ -28,6 +29,11 @@ func resourceIotHubEndpointServiceBusTopic() *pluginsdk.Resource { Update: resourceIotHubEndpointServiceBusTopicCreateUpdate, Delete: resourceIotHubEndpointServiceBusTopicDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubEndpointServiceBusTopicV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.EndpointServiceBusTopicID(id) return err diff --git a/internal/services/iothub/iothub_endpoint_storage_container_resource.go b/internal/services/iothub/iothub_endpoint_storage_container_resource.go index b56cb1bccc2a..4a7f11111005 100644 --- a/internal/services/iothub/iothub_endpoint_storage_container_resource.go +++ b/internal/services/iothub/iothub_endpoint_storage_container_resource.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" iothubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" @@ -29,6 +30,11 @@ func resourceIotHubEndpointStorageContainer() *pluginsdk.Resource { Update: resourceIotHubEndpointStorageContainerCreateUpdate, Delete: resourceIotHubEndpointStorageContainerDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubEndPointStorageContainerV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.EndpointStorageContainerID(id) return err diff --git a/internal/services/iothub/iothub_enrichment_resource.go b/internal/services/iothub/iothub_enrichment_resource.go index 4e48ebc551cb..258e85d036e0 100644 --- a/internal/services/iothub/iothub_enrichment_resource.go +++ b/internal/services/iothub/iothub_enrichment_resource.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -27,6 +28,11 @@ func resourceIotHubEnrichment() *pluginsdk.Resource { Update: resourceArmIotHubEnrichmentCreateUpdate, Delete: resourceArmIotHubEnrichmentDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubEnrichmentV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.EnrichmentID(id) return err diff --git a/internal/services/iothub/iothub_fallback_route_resource.go b/internal/services/iothub/iothub_fallback_route_resource.go index c2a197452441..a76887ba9877 100644 --- a/internal/services/iothub/iothub_fallback_route_resource.go +++ b/internal/services/iothub/iothub_fallback_route_resource.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -23,6 +24,11 @@ func resourceIotHubFallbackRoute() *pluginsdk.Resource { Update: resourceIotHubFallbackRouteCreateUpdate, Delete: resourceIotHubFallbackRouteDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubFallbackRouteV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.FallbackRouteID(id) return err diff --git a/internal/services/iothub/iothub_resource.go b/internal/services/iothub/iothub_resource.go index bad99cd1e631..3c0c786c036f 100644 --- a/internal/services/iothub/iothub_resource.go +++ b/internal/services/iothub/iothub_resource.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" eventhubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" iothubValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" servicebusValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/servicebus/validate" @@ -71,6 +72,11 @@ func resourceIotHub() *pluginsdk.Resource { Update: resourceIotHubCreateUpdate, Delete: resourceIotHubDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.IotHubID(id) return err diff --git a/internal/services/iothub/iothub_route_resource.go b/internal/services/iothub/iothub_route_resource.go index 69cfcfe41186..90d0207e5424 100644 --- a/internal/services/iothub/iothub_route_resource.go +++ b/internal/services/iothub/iothub_route_resource.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -26,6 +27,11 @@ func resourceIotHubRoute() *pluginsdk.Resource { Update: resourceIotHubRouteCreateUpdate, Delete: resourceIotHubRouteDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubRouteV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.RouteID(id) return err diff --git a/internal/services/iothub/iothub_shared_access_policy_resource.go b/internal/services/iothub/iothub_shared_access_policy_resource.go index a0aac2f0551d..c95d8d128806 100644 --- a/internal/services/iothub/iothub_shared_access_policy_resource.go +++ b/internal/services/iothub/iothub_shared_access_policy_resource.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -27,6 +28,11 @@ func resourceIotHubSharedAccessPolicy() *pluginsdk.Resource { Update: resourceIotHubSharedAccessPolicyCreateUpdate, Delete: resourceIotHubSharedAccessPolicyDelete, + SchemaVersion: 1, + StateUpgraders: pluginsdk.StateUpgrades(map[int]pluginsdk.StateUpgrade{ + 0: migration.IoTHubSharedAccessPolicyV0ToV1{}, + }), + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.SharedAccessPolicyID(id) return err diff --git a/internal/services/iothub/migration/certificate_migration_v0_to_v1.go b/internal/services/iothub/migration/certificate_migration_v0_to_v1.go new file mode 100644 index 000000000000..a87f252f06b8 --- /dev/null +++ b/internal/services/iothub/migration/certificate_migration_v0_to_v1.go @@ -0,0 +1,61 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubCertificateV0ToV1 struct{} + +func (s IoTHubCertificateV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "certificate_content": { + Type: pluginsdk.TypeString, + Required: true, + Sensitive: true, + }, + + "is_verified": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + } +} + +func (s IoTHubCertificateV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.IotHubCertificateIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/consumer_group_migration_v0_to_v1.go b/internal/services/iothub/migration/consumer_group_migration_v0_to_v1.go new file mode 100644 index 000000000000..e46edc85c2d1 --- /dev/null +++ b/internal/services/iothub/migration/consumer_group_migration_v0_to_v1.go @@ -0,0 +1,55 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubConsumerGroupV0ToV1 struct{} + +func (s IoTHubConsumerGroupV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "eventhub_endpoint_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + } +} + +func (s IoTHubConsumerGroupV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.ConsumerGroupIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/endpoint_eventhub_migration_v0_to_v1.go b/internal/services/iothub/migration/endpoint_eventhub_migration_v0_to_v1.go new file mode 100644 index 000000000000..76ec815ba28c --- /dev/null +++ b/internal/services/iothub/migration/endpoint_eventhub_migration_v0_to_v1.go @@ -0,0 +1,82 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubEndPointEventHubV0ToV1 struct{} + +func (s IoTHubEndPointEventHubV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + //lintignore: S013 + "iothub_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ConflictsWith: []string{"connection_string"}, + }, + + "endpoint_uri": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"entity_path"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + + "entity_path": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"endpoint_uri"}, + }, + + "connection_string": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ConflictsWith: []string{"identity_id"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + } +} + +func (s IoTHubEndPointEventHubV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.EndpointEventhubIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/endpoint_servicebus_topic_migration_v0_to_v1.go b/internal/services/iothub/migration/endpoint_servicebus_topic_migration_v0_to_v1.go new file mode 100644 index 000000000000..654727c71757 --- /dev/null +++ b/internal/services/iothub/migration/endpoint_servicebus_topic_migration_v0_to_v1.go @@ -0,0 +1,82 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubEndpointServiceBusTopicV0ToV1 struct{} + +func (s IoTHubEndpointServiceBusTopicV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + //lintignore: S013 + "iothub_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ConflictsWith: []string{"connection_string"}, + }, + + "endpoint_uri": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"entity_path"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + + "entity_path": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"endpoint_uri"}, + }, + + "connection_string": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ConflictsWith: []string{"identity_id"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + } +} + +func (s IoTHubEndpointServiceBusTopicV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.EndpointServiceBusTopicIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/endpoint_storage_container_migration_v0_to_v1.go b/internal/services/iothub/migration/endpoint_storage_container_migration_v0_to_v1.go new file mode 100644 index 000000000000..99cda35029f9 --- /dev/null +++ b/internal/services/iothub/migration/endpoint_storage_container_migration_v0_to_v1.go @@ -0,0 +1,104 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubEndPointStorageContainerV0ToV1 struct{} + +func (s IoTHubEndPointStorageContainerV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + //lintignore: S013 + "iothub_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "container_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "file_name_format": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "{iothub}/{partition}/{YYYY}/{MM}/{DD}/{HH}/{mm}", + }, + + "batch_frequency_in_seconds": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 300, + }, + + "max_chunk_size_in_bytes": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 314572800, + }, + + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ConflictsWith: []string{"connection_string"}, + }, + + "endpoint_uri": { + Type: pluginsdk.TypeString, + Optional: true, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + + "connection_string": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ConflictsWith: []string{"identity_id"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + + "encoding": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + } +} + +func (s IoTHubEndPointStorageContainerV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.EndpointStorageContainerIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/enrichment_migration_v0_to_v1.go b/internal/services/iothub/migration/enrichment_migration_v0_to_v1.go new file mode 100644 index 000000000000..7c38ab1fdd71 --- /dev/null +++ b/internal/services/iothub/migration/enrichment_migration_v0_to_v1.go @@ -0,0 +1,63 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubEnrichmentV0ToV1 struct{} + +func (s IoTHubEnrichmentV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "key": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "value": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "endpoint_names": { + Type: pluginsdk.TypeList, + MaxItems: 100, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + Required: true, + }, + } +} + +func (s IoTHubEnrichmentV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.EnrichmentIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/fallback_route_migration_v0_to_v1.go b/internal/services/iothub/migration/fallback_route_migration_v0_to_v1.go new file mode 100644 index 000000000000..ba2eb2642798 --- /dev/null +++ b/internal/services/iothub/migration/fallback_route_migration_v0_to_v1.go @@ -0,0 +1,68 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubFallbackRouteV0ToV1 struct{} + +func (s IoTHubFallbackRouteV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "source": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "condition": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "true", + }, + + "endpoint_names": { + Type: pluginsdk.TypeList, + Required: true, + MaxItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + } +} + +func (s IoTHubFallbackRouteV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.FallbackRouteIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/iothub_migration_v0_to_v1.go b/internal/services/iothub/migration/iothub_migration_v0_to_v1.go new file mode 100644 index 000000000000..a9a4b97f6cdf --- /dev/null +++ b/internal/services/iothub/migration/iothub_migration_v0_to_v1.go @@ -0,0 +1,492 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubV0ToV1 struct{} + +func (s IoTHubV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "sku": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Required: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "capacity": { + Type: pluginsdk.TypeInt, + Required: true, + }, + }, + }, + }, + + "shared_access_policy": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "key_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "primary_key": { + Type: pluginsdk.TypeString, + Computed: true, + Sensitive: true, + }, + "secondary_key": { + Type: pluginsdk.TypeString, + Computed: true, + Sensitive: true, + }, + "permissions": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "event_hub_partition_count": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + }, + "event_hub_retention_in_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + }, + + "file_upload": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "connection_string": { + Type: pluginsdk.TypeString, + Required: true, + Sensitive: true, + }, + "container_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "notifications": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "max_delivery_count": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 10, + }, + "sas_ttl": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + "default_ttl": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + "lock_duration": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + + "endpoint": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "endpoint_uri": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "entity_path": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "connection_string": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + }, + + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "batch_frequency_in_seconds": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 300, + }, + + "max_chunk_size_in_bytes": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 314572800, + }, + + "container_name": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "encoding": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + + "file_name_format": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameOptional(), + }, + }, + }, + + "route": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "source": { + Type: pluginsdk.TypeString, + Required: true, + }, + "condition": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "true", + }, + "endpoint_names": { + Type: pluginsdk.TypeList, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + Required: true, + }, + "enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + }, + }, + }, + + "enrichment": { + Type: pluginsdk.TypeList, + // Currently only 10 enrichments is allowed for standard or basic tier, 2 for Free tier. + MaxItems: 10, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "key": { + Type: pluginsdk.TypeString, + Required: true, + }, + "value": { + Type: pluginsdk.TypeString, + Required: true, + }, + "endpoint_names": { + Type: pluginsdk.TypeList, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + Required: true, + }, + }, + }, + }, + + "fallback_route": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "source": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "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: pluginsdk.TypeString, + Optional: true, + Default: "true", + }, + "endpoint_names": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + }, + }, + }, + }, + + "network_rule_set": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "default_action": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "apply_to_builtin_eventhub_endpoint": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + "ip_rule": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "ip_mask": { + Type: pluginsdk.TypeString, + Required: true, + }, + "action": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "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, + }, + "default_ttl": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "PT1H", + }, + "feedback": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "time_to_live": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "PT1H", + }, + "max_delivery_count": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 10, + }, + "lock_duration": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "PT60S", + }, + }, + }, + }, + }, + }, + }, + + "min_tls_version": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + + "type": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "hostname": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "event_hub_events_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "event_hub_events_namespace": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "event_hub_operations_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "event_hub_events_path": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "event_hub_operations_path": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "identity": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + "identity_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "principal_id": { + Type: schema.TypeString, + Computed: true, + }, + "tenant_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "tags": { + Type: pluginsdk.TypeMap, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + } +} + +func (s IoTHubV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.IotHubIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/route_migration_v0_to_v1.go b/internal/services/iothub/migration/route_migration_v0_to_v1.go new file mode 100644 index 000000000000..b46bac0adb76 --- /dev/null +++ b/internal/services/iothub/migration/route_migration_v0_to_v1.go @@ -0,0 +1,74 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubRouteV0ToV1 struct{} + +func (s IoTHubRouteV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "source": { + Type: pluginsdk.TypeString, + Required: true, + }, + "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: pluginsdk.TypeString, + Optional: true, + Default: "true", + }, + "endpoint_names": { + Type: pluginsdk.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: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + Required: true, + }, + "enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + } +} + +func (s IoTHubRouteV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.RouteIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/servicebus_queue_migration_v0_to_v1.go b/internal/services/iothub/migration/servicebus_queue_migration_v0_to_v1.go new file mode 100644 index 000000000000..037de6702a86 --- /dev/null +++ b/internal/services/iothub/migration/servicebus_queue_migration_v0_to_v1.go @@ -0,0 +1,82 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubServiceBusQueueV0ToV1 struct{} + +func (s IoTHubServiceBusQueueV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + //lintignore: S013 + "iothub_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "authentication_type": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ConflictsWith: []string{"connection_string"}, + }, + + "endpoint_uri": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"entity_path"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + + "entity_path": { + Type: pluginsdk.TypeString, + Optional: true, + RequiredWith: []string{"endpoint_uri"}, + }, + + "connection_string": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ConflictsWith: []string{"identity_id"}, + ExactlyOneOf: []string{"endpoint_uri", "connection_string"}, + }, + } +} + +func (s IoTHubServiceBusQueueV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.EndpointServiceBusQueueIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/migration/shared_access_policy_migration_v0_to_v1.go b/internal/services/iothub/migration/shared_access_policy_migration_v0_to_v1.go new file mode 100644 index 000000000000..87335078aaa2 --- /dev/null +++ b/internal/services/iothub/migration/shared_access_policy_migration_v0_to_v1.go @@ -0,0 +1,97 @@ +package migration + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/iothub/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type IoTHubSharedAccessPolicyV0ToV1 struct{} + +func (s IoTHubSharedAccessPolicyV0ToV1) Schema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "iothub_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "registry_read": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "registry_write": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "service_connect": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "device_connect": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "primary_key": { + Type: pluginsdk.TypeString, + Sensitive: true, + Computed: true, + }, + + "primary_connection_string": { + Type: pluginsdk.TypeString, + Sensitive: true, + Computed: true, + }, + + "secondary_key": { + Type: pluginsdk.TypeString, + Sensitive: true, + Computed: true, + }, + + "secondary_connection_string": { + Type: pluginsdk.TypeString, + Sensitive: true, + Computed: true, + }, + } +} + +func (s IoTHubSharedAccessPolicyV0ToV1) UpgradeFunc() pluginsdk.StateUpgraderFunc { + return func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + oldId := rawState["id"].(string) + newId, err := parse.SharedAccessPolicyIDInsensitively(oldId) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Updating ID from %q to %q", oldId, newId) + + rawState["id"] = newId.ID() + return rawState, nil + } +} diff --git a/internal/services/iothub/parse/consumer_group.go b/internal/services/iothub/parse/consumer_group.go index 27cbae949da1..be1a9bfb5b71 100644 --- a/internal/services/iothub/parse/consumer_group.go +++ b/internal/services/iothub/parse/consumer_group.go @@ -39,7 +39,7 @@ func (id ConsumerGroupId) String() string { } func (id ConsumerGroupId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/eventHubEndpoints/%s/ConsumerGroups/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/eventHubEndpoints/%s/consumerGroups/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.EventHubEndpointName, id.Name) } @@ -63,13 +63,81 @@ func ConsumerGroupID(input string) (*ConsumerGroupId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } if resourceId.EventHubEndpointName, err = id.PopSegment("eventHubEndpoints"); err != nil { return nil, err } - if resourceId.Name, err = id.PopSegment("ConsumerGroups"); err != nil { + if resourceId.Name, err = id.PopSegment("consumerGroups"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// ConsumerGroupIDInsensitively parses an ConsumerGroup ID into an ConsumerGroupId struct, insensitively +// This should only be used to parse an ID for rewriting, the ConsumerGroupID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func ConsumerGroupIDInsensitively(input string) (*ConsumerGroupId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ConsumerGroupId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'eventHubEndpoints' segment + eventHubEndpointsKey := "eventHubEndpoints" + for key := range id.Path { + if strings.EqualFold(key, eventHubEndpointsKey) { + eventHubEndpointsKey = key + break + } + } + if resourceId.EventHubEndpointName, err = id.PopSegment(eventHubEndpointsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'consumerGroups' segment + consumerGroupsKey := "consumerGroups" + for key := range id.Path { + if strings.EqualFold(key, consumerGroupsKey) { + consumerGroupsKey = key + break + } + } + if resourceId.Name, err = id.PopSegment(consumerGroupsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/consumer_group_test.go b/internal/services/iothub/parse/consumer_group_test.go index 11078ae763ba..536a99f403e7 100644 --- a/internal/services/iothub/parse/consumer_group_test.go +++ b/internal/services/iothub/parse/consumer_group_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = ConsumerGroupId{} func TestConsumerGroupIDFormatter(t *testing.T) { actual := NewConsumerGroupID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "events", "group1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/group1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,37 +63,37 @@ func TestConsumerGroupID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing EventHubEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for EventHubEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/", Error: true, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/", Error: true, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/group1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1", Expected: &ConsumerGroupId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -142,3 +142,158 @@ func TestConsumerGroupID(t *testing.T) { } } } + +func TestConsumerGroupIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ConsumerGroupId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing EventHubEndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for EventHubEndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1", + Expected: &ConsumerGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EventHubEndpointName: "events", + Name: "group1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/eventhubendpoints/events/consumergroups/group1", + Expected: &ConsumerGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EventHubEndpointName: "events", + Name: "group1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/EVENTHUBENDPOINTS/events/CONSUMERGROUPS/group1", + Expected: &ConsumerGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EventHubEndpointName: "events", + Name: "group1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EvEnThUbEnDpOiNtS/events/CoNsUmErGrOuPs/group1", + Expected: &ConsumerGroupId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EventHubEndpointName: "events", + Name: "group1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ConsumerGroupIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.EventHubEndpointName != v.Expected.EventHubEndpointName { + t.Fatalf("Expected %q but got %q for EventHubEndpointName", v.Expected.EventHubEndpointName, actual.EventHubEndpointName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/iothub/parse/endpoint_eventhub.go b/internal/services/iothub/parse/endpoint_eventhub.go index 89c57aa280c1..a7772d8bd448 100644 --- a/internal/services/iothub/parse/endpoint_eventhub.go +++ b/internal/services/iothub/parse/endpoint_eventhub.go @@ -36,7 +36,7 @@ func (id EndpointEventhubId) String() string { } func (id EndpointEventhubId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Endpoints/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/endpoints/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.EndpointName) } @@ -60,10 +60,66 @@ func EndpointEventhubID(input string) (*EndpointEventhubId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.EndpointName, err = id.PopSegment("Endpoints"); err != nil { + if resourceId.EndpointName, err = id.PopSegment("endpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// EndpointEventhubIDInsensitively parses an EndpointEventhub ID into an EndpointEventhubId struct, insensitively +// This should only be used to parse an ID for rewriting, the EndpointEventhubID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func EndpointEventhubIDInsensitively(input string) (*EndpointEventhubId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EndpointEventhubId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'endpoints' segment + endpointsKey := "endpoints" + for key := range id.Path { + if strings.EqualFold(key, endpointsKey) { + endpointsKey = key + break + } + } + if resourceId.EndpointName, err = id.PopSegment(endpointsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/endpoint_eventhub_test.go b/internal/services/iothub/parse/endpoint_eventhub_test.go index 67d35a2e8fd9..c6e100224930 100644 --- a/internal/services/iothub/parse/endpoint_eventhub_test.go +++ b/internal/services/iothub/parse/endpoint_eventhub_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = EndpointEventhubId{} func TestEndpointEventhubIDFormatter(t *testing.T) { actual := NewEndpointEventhubID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "eventHubEndpoint1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/eventHubEndpoint1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventHubEndpoint1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestEndpointEventhubID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/eventHubEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventHubEndpoint1", Expected: &EndpointEventhubId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestEndpointEventhubID(t *testing.T) { } } } + +func TestEndpointEventhubIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EndpointEventhubId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventHubEndpoint1", + Expected: &EndpointEventhubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "eventHubEndpoint1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/endpoints/eventHubEndpoint1", + Expected: &EndpointEventhubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "eventHubEndpoint1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ENDPOINTS/eventHubEndpoint1", + Expected: &EndpointEventhubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "eventHubEndpoint1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EnDpOiNtS/eventHubEndpoint1", + Expected: &EndpointEventhubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "eventHubEndpoint1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EndpointEventhubIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.EndpointName != v.Expected.EndpointName { + t.Fatalf("Expected %q but got %q for EndpointName", v.Expected.EndpointName, actual.EndpointName) + } + } +} diff --git a/internal/services/iothub/parse/endpoint_service_bus_queue.go b/internal/services/iothub/parse/endpoint_service_bus_queue.go index fc9686107cfb..6fe96111a553 100644 --- a/internal/services/iothub/parse/endpoint_service_bus_queue.go +++ b/internal/services/iothub/parse/endpoint_service_bus_queue.go @@ -36,7 +36,7 @@ func (id EndpointServiceBusQueueId) String() string { } func (id EndpointServiceBusQueueId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Endpoints/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/endpoints/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.EndpointName) } @@ -60,10 +60,66 @@ func EndpointServiceBusQueueID(input string) (*EndpointServiceBusQueueId, error) return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.EndpointName, err = id.PopSegment("Endpoints"); err != nil { + if resourceId.EndpointName, err = id.PopSegment("endpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// EndpointServiceBusQueueIDInsensitively parses an EndpointServiceBusQueue ID into an EndpointServiceBusQueueId struct, insensitively +// This should only be used to parse an ID for rewriting, the EndpointServiceBusQueueID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func EndpointServiceBusQueueIDInsensitively(input string) (*EndpointServiceBusQueueId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EndpointServiceBusQueueId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'endpoints' segment + endpointsKey := "endpoints" + for key := range id.Path { + if strings.EqualFold(key, endpointsKey) { + endpointsKey = key + break + } + } + if resourceId.EndpointName, err = id.PopSegment(endpointsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/endpoint_service_bus_queue_test.go b/internal/services/iothub/parse/endpoint_service_bus_queue_test.go index dd7800d4ecd3..0a29a5ac8d59 100644 --- a/internal/services/iothub/parse/endpoint_service_bus_queue_test.go +++ b/internal/services/iothub/parse/endpoint_service_bus_queue_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = EndpointServiceBusQueueId{} func TestEndpointServiceBusQueueIDFormatter(t *testing.T) { actual := NewEndpointServiceBusQueueID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "serviceBusQueueEndpoint1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusQueueEndpoint1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusQueueEndpoint1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestEndpointServiceBusQueueID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusQueueEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusQueueEndpoint1", Expected: &EndpointServiceBusQueueId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestEndpointServiceBusQueueID(t *testing.T) { } } } + +func TestEndpointServiceBusQueueIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EndpointServiceBusQueueId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusQueueEndpoint1", + Expected: &EndpointServiceBusQueueId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusQueueEndpoint1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/endpoints/serviceBusQueueEndpoint1", + Expected: &EndpointServiceBusQueueId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusQueueEndpoint1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ENDPOINTS/serviceBusQueueEndpoint1", + Expected: &EndpointServiceBusQueueId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusQueueEndpoint1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EnDpOiNtS/serviceBusQueueEndpoint1", + Expected: &EndpointServiceBusQueueId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusQueueEndpoint1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EndpointServiceBusQueueIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.EndpointName != v.Expected.EndpointName { + t.Fatalf("Expected %q but got %q for EndpointName", v.Expected.EndpointName, actual.EndpointName) + } + } +} diff --git a/internal/services/iothub/parse/endpoint_service_bus_topic.go b/internal/services/iothub/parse/endpoint_service_bus_topic.go index a8ff980470b6..16f6219e4217 100644 --- a/internal/services/iothub/parse/endpoint_service_bus_topic.go +++ b/internal/services/iothub/parse/endpoint_service_bus_topic.go @@ -36,7 +36,7 @@ func (id EndpointServiceBusTopicId) String() string { } func (id EndpointServiceBusTopicId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Endpoints/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/endpoints/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.EndpointName) } @@ -60,10 +60,66 @@ func EndpointServiceBusTopicID(input string) (*EndpointServiceBusTopicId, error) return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.EndpointName, err = id.PopSegment("Endpoints"); err != nil { + if resourceId.EndpointName, err = id.PopSegment("endpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// EndpointServiceBusTopicIDInsensitively parses an EndpointServiceBusTopic ID into an EndpointServiceBusTopicId struct, insensitively +// This should only be used to parse an ID for rewriting, the EndpointServiceBusTopicID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func EndpointServiceBusTopicIDInsensitively(input string) (*EndpointServiceBusTopicId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EndpointServiceBusTopicId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'endpoints' segment + endpointsKey := "endpoints" + for key := range id.Path { + if strings.EqualFold(key, endpointsKey) { + endpointsKey = key + break + } + } + if resourceId.EndpointName, err = id.PopSegment(endpointsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/endpoint_service_bus_topic_test.go b/internal/services/iothub/parse/endpoint_service_bus_topic_test.go index f1042293300a..97621d19f290 100644 --- a/internal/services/iothub/parse/endpoint_service_bus_topic_test.go +++ b/internal/services/iothub/parse/endpoint_service_bus_topic_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = EndpointServiceBusTopicId{} func TestEndpointServiceBusTopicIDFormatter(t *testing.T) { actual := NewEndpointServiceBusTopicID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "serviceBusTopicEndpoint1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusTopicEndpoint1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusTopicEndpoint1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestEndpointServiceBusTopicID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusTopicEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusTopicEndpoint1", Expected: &EndpointServiceBusTopicId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestEndpointServiceBusTopicID(t *testing.T) { } } } + +func TestEndpointServiceBusTopicIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EndpointServiceBusTopicId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusTopicEndpoint1", + Expected: &EndpointServiceBusTopicId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusTopicEndpoint1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/endpoints/serviceBusTopicEndpoint1", + Expected: &EndpointServiceBusTopicId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusTopicEndpoint1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ENDPOINTS/serviceBusTopicEndpoint1", + Expected: &EndpointServiceBusTopicId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusTopicEndpoint1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EnDpOiNtS/serviceBusTopicEndpoint1", + Expected: &EndpointServiceBusTopicId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "serviceBusTopicEndpoint1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EndpointServiceBusTopicIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.EndpointName != v.Expected.EndpointName { + t.Fatalf("Expected %q but got %q for EndpointName", v.Expected.EndpointName, actual.EndpointName) + } + } +} diff --git a/internal/services/iothub/parse/endpoint_storage_container.go b/internal/services/iothub/parse/endpoint_storage_container.go index 917c13bf216e..1dd491b1dd3e 100644 --- a/internal/services/iothub/parse/endpoint_storage_container.go +++ b/internal/services/iothub/parse/endpoint_storage_container.go @@ -36,7 +36,7 @@ func (id EndpointStorageContainerId) String() string { } func (id EndpointStorageContainerId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Endpoints/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/endpoints/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.EndpointName) } @@ -60,10 +60,66 @@ func EndpointStorageContainerID(input string) (*EndpointStorageContainerId, erro return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.EndpointName, err = id.PopSegment("Endpoints"); err != nil { + if resourceId.EndpointName, err = id.PopSegment("endpoints"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// EndpointStorageContainerIDInsensitively parses an EndpointStorageContainer ID into an EndpointStorageContainerId struct, insensitively +// This should only be used to parse an ID for rewriting, the EndpointStorageContainerID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func EndpointStorageContainerIDInsensitively(input string) (*EndpointStorageContainerId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EndpointStorageContainerId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'endpoints' segment + endpointsKey := "endpoints" + for key := range id.Path { + if strings.EqualFold(key, endpointsKey) { + endpointsKey = key + break + } + } + if resourceId.EndpointName, err = id.PopSegment(endpointsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/endpoint_storage_container_test.go b/internal/services/iothub/parse/endpoint_storage_container_test.go index 44217ac872d9..478f766b58f3 100644 --- a/internal/services/iothub/parse/endpoint_storage_container_test.go +++ b/internal/services/iothub/parse/endpoint_storage_container_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = EndpointStorageContainerId{} func TestEndpointStorageContainerIDFormatter(t *testing.T) { actual := NewEndpointStorageContainerID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "storageContainerEndpoint1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/storageContainerEndpoint1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storageContainerEndpoint1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestEndpointStorageContainerID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/storageContainerEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storageContainerEndpoint1", Expected: &EndpointStorageContainerId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestEndpointStorageContainerID(t *testing.T) { } } } + +func TestEndpointStorageContainerIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EndpointStorageContainerId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for EndpointName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storageContainerEndpoint1", + Expected: &EndpointStorageContainerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "storageContainerEndpoint1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/endpoints/storageContainerEndpoint1", + Expected: &EndpointStorageContainerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "storageContainerEndpoint1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ENDPOINTS/storageContainerEndpoint1", + Expected: &EndpointStorageContainerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "storageContainerEndpoint1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EnDpOiNtS/storageContainerEndpoint1", + Expected: &EndpointStorageContainerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + EndpointName: "storageContainerEndpoint1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EndpointStorageContainerIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.EndpointName != v.Expected.EndpointName { + t.Fatalf("Expected %q but got %q for EndpointName", v.Expected.EndpointName, actual.EndpointName) + } + } +} diff --git a/internal/services/iothub/parse/enrichment.go b/internal/services/iothub/parse/enrichment.go index 86c60ea495ba..10765e7f6259 100644 --- a/internal/services/iothub/parse/enrichment.go +++ b/internal/services/iothub/parse/enrichment.go @@ -36,7 +36,7 @@ func (id EnrichmentId) String() string { } func (id EnrichmentId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Enrichments/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/enrichments/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.Name) } @@ -60,10 +60,66 @@ func EnrichmentID(input string) (*EnrichmentId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.Name, err = id.PopSegment("Enrichments"); err != nil { + if resourceId.Name, err = id.PopSegment("enrichments"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// EnrichmentIDInsensitively parses an Enrichment ID into an EnrichmentId struct, insensitively +// This should only be used to parse an ID for rewriting, the EnrichmentID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func EnrichmentIDInsensitively(input string) (*EnrichmentId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EnrichmentId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'enrichments' segment + enrichmentsKey := "enrichments" + for key := range id.Path { + if strings.EqualFold(key, enrichmentsKey) { + enrichmentsKey = key + break + } + } + if resourceId.Name, err = id.PopSegment(enrichmentsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/enrichment_test.go b/internal/services/iothub/parse/enrichment_test.go index 38fee34c926e..b93ebd094802 100644 --- a/internal/services/iothub/parse/enrichment_test.go +++ b/internal/services/iothub/parse/enrichment_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = EnrichmentId{} func TestEnrichmentIDFormatter(t *testing.T) { actual := NewEnrichmentID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "enrichment1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/enrichment1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestEnrichmentID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/enrichment1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1", Expected: &EnrichmentId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestEnrichmentID(t *testing.T) { } } } + +func TestEnrichmentIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EnrichmentId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1", + Expected: &EnrichmentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "enrichment1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/enrichments/enrichment1", + Expected: &EnrichmentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "enrichment1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ENRICHMENTS/enrichment1", + Expected: &EnrichmentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "enrichment1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/EnRiChMeNtS/enrichment1", + Expected: &EnrichmentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "enrichment1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EnrichmentIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/iothub/parse/fallback_route.go b/internal/services/iothub/parse/fallback_route.go index 56742104f7a0..8e7597c43751 100644 --- a/internal/services/iothub/parse/fallback_route.go +++ b/internal/services/iothub/parse/fallback_route.go @@ -36,7 +36,7 @@ func (id FallbackRouteId) String() string { } func (id FallbackRouteId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/FallbackRoute/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/fallbackRoute/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.FallbackRouteName) } @@ -60,10 +60,66 @@ func FallbackRouteID(input string) (*FallbackRouteId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.FallbackRouteName, err = id.PopSegment("FallbackRoute"); err != nil { + if resourceId.FallbackRouteName, err = id.PopSegment("fallbackRoute"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// FallbackRouteIDInsensitively parses an FallbackRoute ID into an FallbackRouteId struct, insensitively +// This should only be used to parse an ID for rewriting, the FallbackRouteID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func FallbackRouteIDInsensitively(input string) (*FallbackRouteId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := FallbackRouteId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'fallbackRoute' segment + fallbackRouteKey := "fallbackRoute" + for key := range id.Path { + if strings.EqualFold(key, fallbackRouteKey) { + fallbackRouteKey = key + break + } + } + if resourceId.FallbackRouteName, err = id.PopSegment(fallbackRouteKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/fallback_route_test.go b/internal/services/iothub/parse/fallback_route_test.go index 7adc3a88e349..9fff69eb1642 100644 --- a/internal/services/iothub/parse/fallback_route_test.go +++ b/internal/services/iothub/parse/fallback_route_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = FallbackRouteId{} func TestFallbackRouteIDFormatter(t *testing.T) { actual := NewFallbackRouteID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "default").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/default" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestFallbackRouteID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing FallbackRouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for FallbackRouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/default", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default", Expected: &FallbackRouteId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestFallbackRouteID(t *testing.T) { } } } + +func TestFallbackRouteIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *FallbackRouteId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing FallbackRouteName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for FallbackRouteName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default", + Expected: &FallbackRouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + FallbackRouteName: "default", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/fallbackroute/default", + Expected: &FallbackRouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + FallbackRouteName: "default", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/FALLBACKROUTE/default", + Expected: &FallbackRouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + FallbackRouteName: "default", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/FaLlBaCkRoUtE/default", + Expected: &FallbackRouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + FallbackRouteName: "default", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := FallbackRouteIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.FallbackRouteName != v.Expected.FallbackRouteName { + t.Fatalf("Expected %q but got %q for FallbackRouteName", v.Expected.FallbackRouteName, actual.FallbackRouteName) + } + } +} diff --git a/internal/services/iothub/parse/iot_hub.go b/internal/services/iothub/parse/iot_hub.go index 0fb2179a9ebd..782625229f61 100644 --- a/internal/services/iothub/parse/iot_hub.go +++ b/internal/services/iothub/parse/iot_hub.go @@ -33,7 +33,7 @@ func (id IotHubId) String() string { } func (id IotHubId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) } @@ -57,7 +57,51 @@ func IotHubID(input string) (*IotHubId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.Name, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.Name, err = id.PopSegment("iotHubs"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// IotHubIDInsensitively parses an IotHub ID into an IotHubId struct, insensitively +// This should only be used to parse an ID for rewriting, the IotHubID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func IotHubIDInsensitively(input string) (*IotHubId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := IotHubId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.Name, err = id.PopSegment(iotHubsKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/iot_hub_certificate.go b/internal/services/iothub/parse/iot_hub_certificate.go index dd591ccbfc62..9520923f1f7a 100644 --- a/internal/services/iothub/parse/iot_hub_certificate.go +++ b/internal/services/iothub/parse/iot_hub_certificate.go @@ -36,7 +36,7 @@ func (id IotHubCertificateId) String() string { } func (id IotHubCertificateId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Certificates/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/certificates/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.CertificateName) } @@ -60,10 +60,66 @@ func IotHubCertificateID(input string) (*IotHubCertificateId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.CertificateName, err = id.PopSegment("Certificates"); err != nil { + if resourceId.CertificateName, err = id.PopSegment("certificates"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// IotHubCertificateIDInsensitively parses an IotHubCertificate ID into an IotHubCertificateId struct, insensitively +// This should only be used to parse an ID for rewriting, the IotHubCertificateID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func IotHubCertificateIDInsensitively(input string) (*IotHubCertificateId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := IotHubCertificateId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'certificates' segment + certificatesKey := "certificates" + for key := range id.Path { + if strings.EqualFold(key, certificatesKey) { + certificatesKey = key + break + } + } + if resourceId.CertificateName, err = id.PopSegment(certificatesKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/iot_hub_certificate_test.go b/internal/services/iothub/parse/iot_hub_certificate_test.go index 6e1012ced167..2d760c37d7d6 100644 --- a/internal/services/iothub/parse/iot_hub_certificate_test.go +++ b/internal/services/iothub/parse/iot_hub_certificate_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = IotHubCertificateId{} func TestIotHubCertificateIDFormatter(t *testing.T) { actual := NewIotHubCertificateID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "cert1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/cert1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/cert1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestIotHubCertificateID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing CertificateName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for CertificateName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/cert1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/cert1", Expected: &IotHubCertificateId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestIotHubCertificateID(t *testing.T) { } } } + +func TestIotHubCertificateIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *IotHubCertificateId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/cert1", + Expected: &IotHubCertificateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + CertificateName: "cert1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/certificates/cert1", + Expected: &IotHubCertificateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + CertificateName: "cert1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/CERTIFICATES/cert1", + Expected: &IotHubCertificateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + CertificateName: "cert1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/CeRtIfIcAtEs/cert1", + Expected: &IotHubCertificateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + CertificateName: "cert1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := IotHubCertificateIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.CertificateName != v.Expected.CertificateName { + t.Fatalf("Expected %q but got %q for CertificateName", v.Expected.CertificateName, actual.CertificateName) + } + } +} diff --git a/internal/services/iothub/parse/iot_hub_test.go b/internal/services/iothub/parse/iot_hub_test.go index 423a4d5e4fcf..7bf9b9cfca44 100644 --- a/internal/services/iothub/parse/iot_hub_test.go +++ b/internal/services/iothub/parse/iot_hub_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = IotHubId{} func TestIotHubIDFormatter(t *testing.T) { actual := NewIotHubID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,13 +63,13 @@ func TestIotHubID(t *testing.T) { { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1", Expected: &IotHubId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -110,3 +110,120 @@ func TestIotHubID(t *testing.T) { } } } + +func TestIotHubIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *IotHubId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1", + Expected: &IotHubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "hub1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1", + Expected: &IotHubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "hub1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1", + Expected: &IotHubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "hub1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1", + Expected: &IotHubId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "hub1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := IotHubIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/iothub/parse/route.go b/internal/services/iothub/parse/route.go index b76dc4d1170e..3f5694042bbf 100644 --- a/internal/services/iothub/parse/route.go +++ b/internal/services/iothub/parse/route.go @@ -36,7 +36,7 @@ func (id RouteId) String() string { } func (id RouteId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/Routes/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/routes/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.Name) } @@ -60,10 +60,66 @@ func RouteID(input string) (*RouteId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.Name, err = id.PopSegment("Routes"); err != nil { + if resourceId.Name, err = id.PopSegment("routes"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// RouteIDInsensitively parses an Route ID into an RouteId struct, insensitively +// This should only be used to parse an ID for rewriting, the RouteID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func RouteIDInsensitively(input string) (*RouteId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := RouteId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'routes' segment + routesKey := "routes" + for key := range id.Path { + if strings.EqualFold(key, routesKey) { + routesKey = key + break + } + } + if resourceId.Name, err = id.PopSegment(routesKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/route_test.go b/internal/services/iothub/parse/route_test.go index 2738a478318a..70cec0810d0a 100644 --- a/internal/services/iothub/parse/route_test.go +++ b/internal/services/iothub/parse/route_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = RouteId{} func TestRouteIDFormatter(t *testing.T) { actual := NewRouteID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "route1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/route1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestRouteID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/route1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1", Expected: &RouteId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestRouteID(t *testing.T) { } } } + +func TestRouteIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *RouteId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1", + Expected: &RouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "route1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/routes/route1", + Expected: &RouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "route1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/ROUTES/route1", + Expected: &RouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "route1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/RoUtEs/route1", + Expected: &RouteId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + Name: "route1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := RouteIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/iothub/parse/shared_access_policy.go b/internal/services/iothub/parse/shared_access_policy.go index 8f1f33267b30..fd02afd7db41 100644 --- a/internal/services/iothub/parse/shared_access_policy.go +++ b/internal/services/iothub/parse/shared_access_policy.go @@ -36,7 +36,7 @@ func (id SharedAccessPolicyId) String() string { } func (id SharedAccessPolicyId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/IotHubs/%s/IotHubKeys/%s" + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Devices/iotHubs/%s/iotHubKeys/%s" return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.IotHubName, id.IotHubKeyName) } @@ -60,10 +60,66 @@ func SharedAccessPolicyID(input string) (*SharedAccessPolicyId, error) { return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") } - if resourceId.IotHubName, err = id.PopSegment("IotHubs"); err != nil { + if resourceId.IotHubName, err = id.PopSegment("iotHubs"); err != nil { return nil, err } - if resourceId.IotHubKeyName, err = id.PopSegment("IotHubKeys"); err != nil { + if resourceId.IotHubKeyName, err = id.PopSegment("iotHubKeys"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} + +// SharedAccessPolicyIDInsensitively parses an SharedAccessPolicy ID into an SharedAccessPolicyId struct, insensitively +// This should only be used to parse an ID for rewriting, the SharedAccessPolicyID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func SharedAccessPolicyIDInsensitively(input string) (*SharedAccessPolicyId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := SharedAccessPolicyId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'iotHubs' segment + iotHubsKey := "iotHubs" + for key := range id.Path { + if strings.EqualFold(key, iotHubsKey) { + iotHubsKey = key + break + } + } + if resourceId.IotHubName, err = id.PopSegment(iotHubsKey); err != nil { + return nil, err + } + + // find the correct casing for the 'iotHubKeys' segment + iotHubKeysKey := "iotHubKeys" + for key := range id.Path { + if strings.EqualFold(key, iotHubKeysKey) { + iotHubKeysKey = key + break + } + } + if resourceId.IotHubKeyName, err = id.PopSegment(iotHubKeysKey); err != nil { return nil, err } diff --git a/internal/services/iothub/parse/shared_access_policy_test.go b/internal/services/iothub/parse/shared_access_policy_test.go index 76f5eeeac2da..33542147231b 100644 --- a/internal/services/iothub/parse/shared_access_policy_test.go +++ b/internal/services/iothub/parse/shared_access_policy_test.go @@ -12,7 +12,7 @@ var _ resourceids.Id = SharedAccessPolicyId{} func TestSharedAccessPolicyIDFormatter(t *testing.T) { actual := NewSharedAccessPolicyID("12345678-1234-9876-4563-123456789012", "resGroup1", "hub1", "sharedAccessPolicy1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/sharedAccessPolicy1" + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/sharedAccessPolicy1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } @@ -63,25 +63,25 @@ func TestSharedAccessPolicyID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Error: true, }, { // missing IotHubKeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Error: true, }, { // missing value for IotHubKeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/", Error: true, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/sharedAccessPolicy1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/sharedAccessPolicy1", Expected: &SharedAccessPolicyId{ SubscriptionId: "12345678-1234-9876-4563-123456789012", ResourceGroup: "resGroup1", @@ -126,3 +126,139 @@ func TestSharedAccessPolicyID(t *testing.T) { } } } + +func TestSharedAccessPolicyIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *SharedAccessPolicyId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/", + Error: true, + }, + + { + // missing value for IotHubName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", + Error: true, + }, + + { + // missing IotHubKeyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", + Error: true, + }, + + { + // missing value for IotHubKeyName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/sharedAccessPolicy1", + Expected: &SharedAccessPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + IotHubKeyName: "sharedAccessPolicy1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iothubs/hub1/iothubkeys/sharedAccessPolicy1", + Expected: &SharedAccessPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + IotHubKeyName: "sharedAccessPolicy1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IOTHUBS/hub1/IOTHUBKEYS/sharedAccessPolicy1", + Expected: &SharedAccessPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + IotHubKeyName: "sharedAccessPolicy1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IoThUbS/hub1/IoThUbKeYs/sharedAccessPolicy1", + Expected: &SharedAccessPolicyId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + IotHubName: "hub1", + IotHubKeyName: "sharedAccessPolicy1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := SharedAccessPolicyIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.IotHubName != v.Expected.IotHubName { + t.Fatalf("Expected %q but got %q for IotHubName", v.Expected.IotHubName, actual.IotHubName) + } + if actual.IotHubKeyName != v.Expected.IotHubKeyName { + t.Fatalf("Expected %q but got %q for IotHubKeyName", v.Expected.IotHubKeyName, actual.IotHubKeyName) + } + } +} diff --git a/internal/services/iothub/resourceids.go b/internal/services/iothub/resourceids.go index 5cee89e3a12d..318be083a8bc 100644 --- a/internal/services/iothub/resourceids.go +++ b/internal/services/iothub/resourceids.go @@ -1,13 +1,13 @@ package iothub -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Enrichment -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/enrichment1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IotHub -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ConsumerGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/group1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FallbackRoute -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/default -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Route -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/route1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SharedAccessPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/sharedAccessPolicy1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointStorageContainer -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/storageContainerEndpoint1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointServiceBusTopic -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusTopicEndpoint1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointServiceBusQueue -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusQueueEndpoint1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointEventhub -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/eventHubEndpoint1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IotHubCertificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/cert1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Enrichment -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IotHub -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ConsumerGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FallbackRoute -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Route -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SharedAccessPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/sharedAccessPolicy1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointStorageContainer -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storageContainerEndpoint1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointServiceBusTopic -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusTopicEndpoint1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointServiceBusQueue -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusQueueEndpoint1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EndpointEventhub -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventHubEndpoint1 -rewrite=true +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IotHubCertificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/cert1 -rewrite=true diff --git a/internal/services/iothub/validate/consumer_group_id_test.go b/internal/services/iothub/validate/consumer_group_id_test.go index c578e1953edb..ca89eb1b7fba 100644 --- a/internal/services/iothub/validate/consumer_group_id_test.go +++ b/internal/services/iothub/validate/consumer_group_id_test.go @@ -48,37 +48,37 @@ func TestConsumerGroupID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing EventHubEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for EventHubEndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/", Valid: false, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/", Valid: false, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/group1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1", Valid: true, }, diff --git a/internal/services/iothub/validate/endpoint_eventhub_id_test.go b/internal/services/iothub/validate/endpoint_eventhub_id_test.go index 0eb55a2f0d27..66d5c85f5cfb 100644 --- a/internal/services/iothub/validate/endpoint_eventhub_id_test.go +++ b/internal/services/iothub/validate/endpoint_eventhub_id_test.go @@ -48,25 +48,25 @@ func TestEndpointEventhubID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/eventHubEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventHubEndpoint1", Valid: true, }, diff --git a/internal/services/iothub/validate/endpoint_service_bus_queue_id_test.go b/internal/services/iothub/validate/endpoint_service_bus_queue_id_test.go index fb9ddc95172e..ba5c393919b1 100644 --- a/internal/services/iothub/validate/endpoint_service_bus_queue_id_test.go +++ b/internal/services/iothub/validate/endpoint_service_bus_queue_id_test.go @@ -48,25 +48,25 @@ func TestEndpointServiceBusQueueID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusQueueEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusQueueEndpoint1", Valid: true, }, diff --git a/internal/services/iothub/validate/endpoint_service_bus_topic_id_test.go b/internal/services/iothub/validate/endpoint_service_bus_topic_id_test.go index ee3dbff4d436..e2d423b4b408 100644 --- a/internal/services/iothub/validate/endpoint_service_bus_topic_id_test.go +++ b/internal/services/iothub/validate/endpoint_service_bus_topic_id_test.go @@ -48,25 +48,25 @@ func TestEndpointServiceBusTopicID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/serviceBusTopicEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/serviceBusTopicEndpoint1", Valid: true, }, diff --git a/internal/services/iothub/validate/endpoint_storage_container_id_test.go b/internal/services/iothub/validate/endpoint_storage_container_id_test.go index 7874b43c1615..03cc7d6e906e 100644 --- a/internal/services/iothub/validate/endpoint_storage_container_id_test.go +++ b/internal/services/iothub/validate/endpoint_storage_container_id_test.go @@ -48,25 +48,25 @@ func TestEndpointStorageContainerID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for EndpointName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/storageContainerEndpoint1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storageContainerEndpoint1", Valid: true, }, diff --git a/internal/services/iothub/validate/enrichment_id_test.go b/internal/services/iothub/validate/enrichment_id_test.go index d35a2092b22f..fda4cd761e82 100644 --- a/internal/services/iothub/validate/enrichment_id_test.go +++ b/internal/services/iothub/validate/enrichment_id_test.go @@ -48,25 +48,25 @@ func TestEnrichmentID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/enrichment1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1", Valid: true, }, diff --git a/internal/services/iothub/validate/fallback_route_id_test.go b/internal/services/iothub/validate/fallback_route_id_test.go index 26171dd94f75..6215fd008c92 100644 --- a/internal/services/iothub/validate/fallback_route_id_test.go +++ b/internal/services/iothub/validate/fallback_route_id_test.go @@ -48,25 +48,25 @@ func TestFallbackRouteID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing FallbackRouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for FallbackRouteName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/default", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default", Valid: true, }, diff --git a/internal/services/iothub/validate/iot_hub_certificate_id_test.go b/internal/services/iothub/validate/iot_hub_certificate_id_test.go index f3bb1faf0487..7232f33a7647 100644 --- a/internal/services/iothub/validate/iot_hub_certificate_id_test.go +++ b/internal/services/iothub/validate/iot_hub_certificate_id_test.go @@ -48,25 +48,25 @@ func TestIotHubCertificateID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing CertificateName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for CertificateName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Certificates/cert1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/certificates/cert1", Valid: true, }, diff --git a/internal/services/iothub/validate/iot_hub_id_test.go b/internal/services/iothub/validate/iot_hub_id_test.go index 13d9349783b9..ee530b6e9bfd 100644 --- a/internal/services/iothub/validate/iot_hub_id_test.go +++ b/internal/services/iothub/validate/iot_hub_id_test.go @@ -48,13 +48,13 @@ func TestIotHubID(t *testing.T) { { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1", Valid: true, }, diff --git a/internal/services/iothub/validate/route_id_test.go b/internal/services/iothub/validate/route_id_test.go index 4b6b2375085c..393226f69c8f 100644 --- a/internal/services/iothub/validate/route_id_test.go +++ b/internal/services/iothub/validate/route_id_test.go @@ -48,25 +48,25 @@ func TestRouteID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for Name - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/route1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1", Valid: true, }, diff --git a/internal/services/iothub/validate/shared_access_policy_id_test.go b/internal/services/iothub/validate/shared_access_policy_id_test.go index f5aa9c469909..42a798da8245 100644 --- a/internal/services/iothub/validate/shared_access_policy_id_test.go +++ b/internal/services/iothub/validate/shared_access_policy_id_test.go @@ -48,25 +48,25 @@ func TestSharedAccessPolicyID(t *testing.T) { { // missing value for IotHubName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/", Valid: false, }, { // missing IotHubKeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/", Valid: false, }, { // missing value for IotHubKeyName - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/", Valid: false, }, { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/sharedAccessPolicy1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/sharedAccessPolicy1", Valid: true, }, diff --git a/website/docs/r/iothub.html.markdown b/website/docs/r/iothub.html.markdown index fe50cc946777..ef5f7714ab9f 100644 --- a/website/docs/r/iothub.html.markdown +++ b/website/docs/r/iothub.html.markdown @@ -378,5 +378,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHubs can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub.hub1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1 +terraform import azurerm_iothub.hub1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1 ``` diff --git a/website/docs/r/iothub_certificate.html.markdown b/website/docs/r/iothub_certificate.html.markdown index 8f96d7e8814c..4cb40f4d1203 100644 --- a/website/docs/r/iothub_certificate.html.markdown +++ b/website/docs/r/iothub_certificate.html.markdown @@ -73,5 +73,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Certificates can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_certificate.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/example/Certificates/example +terraform import azurerm_iothub_certificate.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/example/certificates/example ``` diff --git a/website/docs/r/iothub_consumer_group.html.markdown b/website/docs/r/iothub_consumer_group.html.markdown index eca34cd5206b..9acf873b9a56 100644 --- a/website/docs/r/iothub_consumer_group.html.markdown +++ b/website/docs/r/iothub_consumer_group.html.markdown @@ -73,5 +73,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Consumer Groups can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_consumer_group.group1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/eventHubEndpoints/events/ConsumerGroups/group1 +terraform import azurerm_iothub_consumer_group.group1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/eventHubEndpoints/events/consumerGroups/group1 ``` diff --git a/website/docs/r/iothub_endpoint_eventhub.html.markdown b/website/docs/r/iothub_endpoint_eventhub.html.markdown index e742d488531d..52683de10d45 100644 --- a/website/docs/r/iothub_endpoint_eventhub.html.markdown +++ b/website/docs/r/iothub_endpoint_eventhub.html.markdown @@ -112,5 +112,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub EventHub Endpoint can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_endpoint_eventhub.eventhub1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/eventhub_endpoint1 +terraform import azurerm_iothub_endpoint_eventhub.eventhub1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/eventhub_endpoint1 ``` diff --git a/website/docs/r/iothub_endpoint_servicebus_queue.html.markdown b/website/docs/r/iothub_endpoint_servicebus_queue.html.markdown index ce1f7c9148e3..2260fd316589 100644 --- a/website/docs/r/iothub_endpoint_servicebus_queue.html.markdown +++ b/website/docs/r/iothub_endpoint_servicebus_queue.html.markdown @@ -107,7 +107,7 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l ## Import IoTHub ServiceBus Queue Endpoint can be imported using the `resource id`, e.g. - +g ```shell -terraform import azurerm_iothub_endpoint_servicebus_queue.servicebus_queue1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/servicebusqueue_endpoint1 +terraform import azurerm_iothub_endpoint_servicebus_queue.servicebus_queue1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/servicebusqueue_endpoint1 ``` diff --git a/website/docs/r/iothub_endpoint_servicebus_topic.html.markdown b/website/docs/r/iothub_endpoint_servicebus_topic.html.markdown index 591a957e1eda..45adc8f21050 100644 --- a/website/docs/r/iothub_endpoint_servicebus_topic.html.markdown +++ b/website/docs/r/iothub_endpoint_servicebus_topic.html.markdown @@ -107,5 +107,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub ServiceBus Topic Endpoint can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_endpoint_servicebus_topic.servicebus_topic1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/servicebustopic_endpoint1 +terraform import azurerm_iothub_endpoint_servicebus_topic.servicebus_topic1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/servicebustopic_endpoint1 ``` diff --git a/website/docs/r/iothub_endpoint_storage_container.html.markdown b/website/docs/r/iothub_endpoint_storage_container.html.markdown index cc765a1a85f3..6c70b8d8b2c8 100644 --- a/website/docs/r/iothub_endpoint_storage_container.html.markdown +++ b/website/docs/r/iothub_endpoint_storage_container.html.markdown @@ -110,5 +110,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Storage Container Endpoint can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_endpoint_storage_container.storage_container1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Endpoints/storage_container_endpoint1 +terraform import azurerm_iothub_endpoint_storage_container.storage_container1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/endpoints/storage_container_endpoint1 ``` diff --git a/website/docs/r/iothub_enrichment.html.markdown b/website/docs/r/iothub_enrichment.html.markdown index e1059ddafb8f..46a9357d119d 100644 --- a/website/docs/r/iothub_enrichment.html.markdown +++ b/website/docs/r/iothub_enrichment.html.markdown @@ -113,5 +113,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Enrichment can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_enrichment.enrichment1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Enrichments/enrichment1 +terraform import azurerm_iothub_enrichment.enrichment1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/enrichments/enrichment1 ``` diff --git a/website/docs/r/iothub_fallback_route.html.markdown b/website/docs/r/iothub_fallback_route.html.markdown index a8e280c93a46..21443e23cb62 100644 --- a/website/docs/r/iothub_fallback_route.html.markdown +++ b/website/docs/r/iothub_fallback_route.html.markdown @@ -112,7 +112,7 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Fallback Route can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_fallback_route.route1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/FallbackRoute/default +terraform import azurerm_iothub_fallback_route.route1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/fallbackRoute/default ``` -~> **NOTE:** As there may only be a single fallback route per IoTHub, the id always ends with `/FallbackRoute/default`. +~> **NOTE:** As there may only be a single fallback route per IoTHub, the id always ends with `/fallbackRoute/default`. diff --git a/website/docs/r/iothub_route.html.markdown b/website/docs/r/iothub_route.html.markdown index 721f0c018680..1fd1e5895914 100644 --- a/website/docs/r/iothub_route.html.markdown +++ b/website/docs/r/iothub_route.html.markdown @@ -112,5 +112,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Route can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_route.route1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/Routes/route1 +terraform import azurerm_iothub_route.route1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/routes/route1 ``` diff --git a/website/docs/r/iothub_shared_access_policy.html.markdown b/website/docs/r/iothub_shared_access_policy.html.markdown index 98c22585bd35..81d38c8f98fd 100644 --- a/website/docs/r/iothub_shared_access_policy.html.markdown +++ b/website/docs/r/iothub_shared_access_policy.html.markdown @@ -89,5 +89,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l IoTHub Shared Access Policies can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_iothub_shared_access_policy.shared_access_policy1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/IotHubs/hub1/IotHubKeys/shared_access_policy1 +terraform import azurerm_iothub_shared_access_policy.shared_access_policy1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Devices/iotHubs/hub1/iotHubKeys/shared_access_policy1 ```