Skip to content

Commit

Permalink
storage - fix tests for 4.0 (#26949)
Browse files Browse the repository at this point in the history
* storage - fix tests for 4.0

* azurerm_storage_table_entities - now supports storage_table_id

* lint
  • Loading branch information
mbfrahry authored Aug 9, 2024
1 parent 7a32f05 commit d54b72a
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 60 deletions.
104 changes: 87 additions & 17 deletions internal/services/storage/storage_table_entities_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,28 @@ import (
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/client"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate"
storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/blob/accounts"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/table/entities"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/table/tables"
)

type storageTableEntitiesDataSource struct{}

var _ sdk.DataSource = storageTableEntitiesDataSource{}

type TableEntitiesDataSourceModel struct {
TableName string `tfschema:"table_name"`
StorageAccountName string `tfschema:"storage_account_name"`
StorageTableId string `tfschema:"storage_table_id"`
TableName string `tfschema:"table_name,removedInNextMajorVersion"`
StorageAccountName string `tfschema:"storage_account_name,removedInNextMajorVersion"`
Filter string `tfschema:"filter"`
Select []string `tfschema:"select"`
Items []TableEntityDataSourceModel `tfschema:"items"`
Expand All @@ -37,17 +44,11 @@ type TableEntityDataSourceModel struct {
}

func (k storageTableEntitiesDataSource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"table_name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.StorageTableName,
},

"storage_account_name": {
s := map[string]*pluginsdk.Schema{
"storage_table_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.StorageAccountName,
ValidateFunc: storageValidate.StorageTableDataPlaneID,
},

"filter": {
Expand All @@ -64,6 +65,35 @@ func (k storageTableEntitiesDataSource) Arguments() map[string]*pluginsdk.Schema
},
},
}

if !features.FourPointOhBeta() {
s["storage_table_id"].Required = false
s["storage_table_id"].Optional = true
s["storage_table_id"].Computed = true
s["storage_table_id"].ConflictsWith = []string{"table_name", "storage_account_name"}

s["table_name"] = &pluginsdk.Schema{
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
Deprecated: "the `table_name` and `storage_account_name` properties have been superseded by the `storage_table_id` property and will be removed in version 4.0 of the AzureRM provider",
ConflictsWith: []string{"storage_table_id"},
RequiredWith: []string{"storage_account_name"},
ValidateFunc: validate.StorageTableName,
}

s["storage_account_name"] = &pluginsdk.Schema{
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
Deprecated: "the `table_name` and `storage_account_name` properties have been superseded by the `storage_table_id` property and will be removed in version 4.0 of the AzureRM provider",
ConflictsWith: []string{"storage_table_id"},
RequiredWith: []string{"table_name"},
ValidateFunc: validate.StorageAccountName,
}
}

return s
}

func (k storageTableEntitiesDataSource) Attributes() map[string]*pluginsdk.Schema {
Expand Down Expand Up @@ -114,13 +144,53 @@ func (k storageTableEntitiesDataSource) Read() sdk.ResourceFunc {
}

storageClient := metadata.Client.Storage
subscriptionId := metadata.Client.Account.SubscriptionId

var storageTableId *tables.TableId
var err error
if model.StorageTableId != "" {
storageTableId, err = tables.ParseTableID(model.StorageTableId, storageClient.StorageDomainSuffix)
if err != nil {
return err
}
} else if !features.FourPointOhBeta() {
// TODO: this is needed until `table_name` / `storage_account_name` are removed in favor of `storage_table_id` in v4.0
// we will retrieve the storage account twice but this will make it easier to refactor later
storageAccountName := model.StorageAccountName

account, err := storageClient.FindAccount(ctx, subscriptionId, storageAccountName)
if err != nil {
return fmt.Errorf("retrieving Account %q: %v", storageAccountName, err)
}
if account == nil {
return fmt.Errorf("locating Storage Account %q", storageAccountName)
}

// Determine the table endpoint, so we can build a data plane ID
endpoint, err := account.DataPlaneEndpoint(client.EndpointTypeTable)
if err != nil {
return fmt.Errorf("determining Table endpoint: %v", err)
}

// Parse the table endpoint as a data plane account ID
accountId, err := accounts.ParseAccountID(*endpoint, storageClient.StorageDomainSuffix)
if err != nil {
return fmt.Errorf("parsing Account ID: %v", err)
}

storageTableId = pointer.To(tables.NewTableID(*accountId, model.TableName))
}

if storageTableId == nil {
return fmt.Errorf("determining storage table ID")
}

account, err := storageClient.FindAccount(ctx, metadata.Client.Account.SubscriptionId, model.StorageAccountName)
account, err := storageClient.FindAccount(ctx, subscriptionId, storageTableId.AccountId.AccountName)
if err != nil {
return fmt.Errorf("retrieving Account %q for Table %q: %s", model.StorageAccountName, model.TableName, err)
return fmt.Errorf("retrieving Account %q for Table %q: %v", storageTableId.AccountId.AccountName, storageTableId.TableName, err)
}
if account == nil {
return fmt.Errorf("the parent Storage Account %s was not found", model.StorageAccountName)
return fmt.Errorf("the parent Storage Account %s was not found", storageTableId.AccountId.AccountName)
}

client, err := storageClient.TableEntityDataPlaneClient(ctx, *account, storageClient.DataPlaneOperationSupportingAnyAuthMethod())
Expand All @@ -138,11 +208,11 @@ func (k storageTableEntitiesDataSource) Read() sdk.ResourceFunc {
input.PropertyNamesToSelect = &model.Select
}

id := parse.NewStorageTableEntitiesId(model.StorageAccountName, storageClient.StorageDomainSuffix, model.TableName, model.Filter)
id := parse.NewStorageTableEntitiesId(storageTableId.AccountId.AccountName, storageClient.StorageDomainSuffix, storageTableId.TableName, model.Filter)

result, err := client.Query(ctx, model.TableName, input)
result, err := client.Query(ctx, storageTableId.TableName, input)
if err != nil {
return fmt.Errorf("retrieving Entities (Filter %q) (Table %q in %s): %+v", model.Filter, model.TableName, account.StorageAccountId, err)
return fmt.Errorf("retrieving Entities (Filter %q) (Table %q in %s): %+v", model.Filter, storageTableId.TableName, account.StorageAccountId, err)
}

var flattenedEntities []TableEntityDataSourceModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ resource "azurerm_storage_table" "test" {
}
resource "azurerm_storage_table_entity" "test" {
storage_account_name = azurerm_storage_account.test.name
table_name = azurerm_storage_table.test.name
storage_table_id = azurerm_storage_table.test.id
partition_key = "testpartition"
row_key = "testrow"
Expand All @@ -81,8 +80,7 @@ resource "azurerm_storage_table_entity" "test" {
}
resource "azurerm_storage_table_entity" "test2" {
storage_account_name = azurerm_storage_account.test.name
table_name = azurerm_storage_table.test.name
storage_table_id = azurerm_storage_table.test.id
partition_key = "testpartition"
row_key = "testrow2"
Expand All @@ -94,8 +92,7 @@ resource "azurerm_storage_table_entity" "test2" {
}
resource "azurerm_storage_table_entity" "testselector" {
storage_account_name = azurerm_storage_account.test.name
table_name = azurerm_storage_table.test.name
storage_table_id = azurerm_storage_table.test.id
partition_key = "testselectorpartition"
row_key = "testrow"
Expand All @@ -115,9 +112,8 @@ func (d StorageTableEntitiesDataSource) basicWithDataSource(data acceptance.Test
%s
data "azurerm_storage_table_entities" "test" {
table_name = azurerm_storage_table_entity.test.table_name
storage_account_name = azurerm_storage_table_entity.test.storage_account_name
filter = "PartitionKey eq 'testpartition'"
storage_table_id = azurerm_storage_table.test.id
filter = "PartitionKey eq 'testpartition'"
depends_on = [
azurerm_storage_table_entity.test,
Expand All @@ -133,10 +129,9 @@ func (d StorageTableEntitiesDataSource) basicWithDataSourceAndSelector(data acce
%s
data "azurerm_storage_table_entities" "test" {
table_name = azurerm_storage_table_entity.test.table_name
storage_account_name = azurerm_storage_table_entity.test.storage_account_name
filter = "PartitionKey eq 'testselectorpartition'"
select = ["testselector"]
storage_table_id = azurerm_storage_table.test.id
filter = "PartitionKey eq 'testselectorpartition'"
select = ["testselector"]
depends_on = [
azurerm_storage_table_entity.test,
Expand Down
104 changes: 86 additions & 18 deletions internal/services/storage/storage_table_entity_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,33 @@ import (
"fmt"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/client"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate"
storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/blob/accounts"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/table/entities"
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/table/tables"
)

func dataSourceStorageTableEntity() *pluginsdk.Resource {
return &pluginsdk.Resource{
resource := &pluginsdk.Resource{
Read: dataSourceStorageTableEntityRead,

Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"table_name": {
"storage_table_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.StorageTableName,
},

"storage_account_name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.StorageAccountName,
ValidateFunc: storageValidate.StorageTableDataPlaneID,
},

"partition_key": {
Expand All @@ -59,6 +57,35 @@ func dataSourceStorageTableEntity() *pluginsdk.Resource {
},
},
}

if !features.FourPointOhBeta() {
resource.Schema["storage_table_id"].Required = false
resource.Schema["storage_table_id"].Optional = true
resource.Schema["storage_table_id"].Computed = true
resource.Schema["storage_table_id"].ConflictsWith = []string{"table_name", "storage_account_name"}

resource.Schema["table_name"] = &pluginsdk.Schema{
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
Deprecated: "the `table_name` and `storage_account_name` properties have been superseded by the `storage_table_id` property and will be removed in version 4.0 of the AzureRM provider",
ConflictsWith: []string{"storage_table_id"},
RequiredWith: []string{"storage_account_name"},
ValidateFunc: validate.StorageTableName,
}

resource.Schema["storage_account_name"] = &pluginsdk.Schema{
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
Deprecated: "the `table_name` and `storage_account_name` properties have been superseded by the `storage_table_id` property and will be removed in version 4.0 of the AzureRM provider",
ConflictsWith: []string{"storage_table_id"},
RequiredWith: []string{"table_name"},
ValidateFunc: validate.StorageAccountName,
}
}

return resource
}

func dataSourceStorageTableEntityRead(d *pluginsdk.ResourceData, meta interface{}) error {
Expand All @@ -67,17 +94,54 @@ func dataSourceStorageTableEntityRead(d *pluginsdk.ResourceData, meta interface{
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

accountName := d.Get("storage_account_name").(string)
tableName := d.Get("table_name").(string)
partitionKey := d.Get("partition_key").(string)
rowKey := d.Get("row_key").(string)

account, err := storageClient.FindAccount(ctx, subscriptionId, accountName)
var storageTableId *tables.TableId
var err error
if v, ok := d.GetOk("storage_table_id"); ok && v.(string) != "" {
storageTableId, err = tables.ParseTableID(v.(string), storageClient.StorageDomainSuffix)
if err != nil {
return err
}
} else if !features.FourPointOhBeta() {
// TODO: this is needed until `table_name` / `storage_account_name` are removed in favor of `storage_table_id` in v4.0
// we will retrieve the storage account twice but this will make it easier to refactor later
storageAccountName := d.Get("storage_account_name").(string)

account, err := storageClient.FindAccount(ctx, subscriptionId, storageAccountName)
if err != nil {
return fmt.Errorf("retrieving Account %q: %v", storageAccountName, err)
}
if account == nil {
return fmt.Errorf("locating Storage Account %q", storageAccountName)
}

// Determine the table endpoint, so we can build a data plane ID
endpoint, err := account.DataPlaneEndpoint(client.EndpointTypeTable)
if err != nil {
return fmt.Errorf("determining Table endpoint: %v", err)
}

// Parse the table endpoint as a data plane account ID
accountId, err := accounts.ParseAccountID(*endpoint, storageClient.StorageDomainSuffix)
if err != nil {
return fmt.Errorf("parsing Account ID: %v", err)
}

storageTableId = pointer.To(tables.NewTableID(*accountId, d.Get("table_name").(string)))
}

if storageTableId == nil {
return fmt.Errorf("determining storage table ID")
}

account, err := storageClient.FindAccount(ctx, subscriptionId, storageTableId.AccountId.AccountName)
if err != nil {
return fmt.Errorf("retrieving Account %q for Table %q: %v", accountName, tableName, err)
return fmt.Errorf("retrieving Account %q for Table %q: %v", storageTableId.AccountId.AccountName, storageTableId.TableName, err)
}
if account == nil {
return fmt.Errorf("the parent Storage Account %s was not found", accountName)
return fmt.Errorf("the parent Storage Account %s was not found", storageTableId.AccountId.AccountName)
}

dataPlaneClient, err := storageClient.TableEntityDataPlaneClient(ctx, *account, storageClient.DataPlaneOperationSupportingAnyAuthMethod())
Expand All @@ -95,24 +159,28 @@ func dataSourceStorageTableEntityRead(d *pluginsdk.ResourceData, meta interface{
return fmt.Errorf("parsing Account ID: %v", err)
}

id := entities.NewEntityID(*accountId, tableName, partitionKey, rowKey)
id := entities.NewEntityID(*accountId, storageTableId.TableName, partitionKey, rowKey)

input := entities.GetEntityInput{
PartitionKey: partitionKey,
RowKey: rowKey,
MetaDataLevel: entities.NoMetaData,
}

result, err := dataPlaneClient.Get(ctx, tableName, input)
result, err := dataPlaneClient.Get(ctx, storageTableId.TableName, input)
if err != nil {
return fmt.Errorf("retrieving %s: %v", id, err)
}

d.Set("storage_account_name", accountName)
d.Set("table_name", tableName)
d.Set("storage_table_id", storageTableId.ID())
d.Set("partition_key", partitionKey)
d.Set("row_key", rowKey)

if !features.FourPointOhBeta() {
d.Set("storage_account_name", id.AccountId.AccountName)
d.Set("table_name", id.TableName)
}

if err = d.Set("entity", flattenEntity(result.Entity)); err != nil {
return fmt.Errorf("setting `entity` for %s: %v", id, err)
}
Expand Down
Loading

0 comments on commit d54b72a

Please sign in to comment.