blob: 61197a705d04eee0aa668ce04ebfe10fbd1c703d [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package azure
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/storage/2023-01-01/storageaccounts"
"github.com/hashicorp/go-azure-sdk/sdk/environments"
)
// This file is referencing the terraform-provider-azurerm: internal/services/storage/client/helpers.go
type EndpointType string
const (
EndpointTypeBlob = "blob"
EndpointTypeDfs = "dfs"
EndpointTypeFile = "file"
EndpointTypeQueue = "queue"
EndpointTypeTable = "table"
)
type AccountDetails struct {
Kind storageaccounts.Kind
IsHnsEnabled bool
StorageAccountId commonids.StorageAccountId
accountKey *string
// primaryBlobEndpoint is the Primary Blob Endpoint for the Data Plane API for this Storage Account
// e.g. `https://{account}.blob.core.windows.net`
primaryBlobEndpoint *string
// primaryDfsEndpoint is the Primary Dfs Endpoint for the Data Plane API for this Storage Account
// e.g. `https://sale.dfs.core.windows.net`
primaryDfsEndpoint *string
// primaryFileEndpoint is the Primary File Endpoint for the Data Plane API for this Storage Account
// e.g. `https://{account}.file.core.windows.net`
primaryFileEndpoint *string
// primaryQueueEndpoint is the Primary Queue Endpoint for the Data Plane API for this Storage Account
// e.g. `https://{account}.queue.core.windows.net`
primaryQueueEndpoint *string
// primaryTableEndpoint is the Primary Table Endpoint for the Data Plane API for this Storage Account
// e.g. `https://{account}.table.core.windows.net`
primaryTableEndpoint *string
}
func (ad *AccountDetails) AccountKey(ctx context.Context, client *storageaccounts.StorageAccountsClient) (*string, error) {
if ad.accountKey != nil {
return ad.accountKey, nil
}
opts := storageaccounts.DefaultListKeysOperationOptions()
opts.Expand = pointer.To(storageaccounts.ListKeyExpandKerb)
listKeysResp, err := client.ListKeys(ctx, ad.StorageAccountId, opts)
if err != nil {
return nil, fmt.Errorf("listing Keys for %s: %+v", ad.StorageAccountId, err)
}
if model := listKeysResp.Model; model != nil && model.Keys != nil {
for _, key := range *model.Keys {
if key.Permissions == nil || key.Value == nil {
continue
}
if *key.Permissions == storageaccounts.KeyPermissionFull {
ad.accountKey = key.Value
break
}
}
}
if ad.accountKey == nil {
return nil, fmt.Errorf("unable to determine the Write Key for %s", ad.StorageAccountId)
}
return ad.accountKey, nil
}
func (ad *AccountDetails) DataPlaneEndpoint(endpointType EndpointType) (*string, error) {
var baseUri *string
switch endpointType {
case EndpointTypeBlob:
baseUri = ad.primaryBlobEndpoint
case EndpointTypeDfs:
baseUri = ad.primaryDfsEndpoint
case EndpointTypeFile:
baseUri = ad.primaryFileEndpoint
case EndpointTypeQueue:
baseUri = ad.primaryQueueEndpoint
case EndpointTypeTable:
baseUri = ad.primaryTableEndpoint
default:
return nil, fmt.Errorf("internal-error: unrecognised endpoint type %q when building storage client", endpointType)
}
if baseUri == nil {
return nil, fmt.Errorf("determining %s endpoint for %s: missing primary endpoint", endpointType, ad.StorageAccountId)
}
return baseUri, nil
}
func populateAccountDetails(accountId commonids.StorageAccountId, account storageaccounts.StorageAccount) (*AccountDetails, error) {
out := AccountDetails{
Kind: pointer.From(account.Kind),
StorageAccountId: accountId,
}
if account.Properties == nil {
return nil, fmt.Errorf("populating details for %s: `model.Properties` was nil", accountId)
}
if account.Properties.PrimaryEndpoints == nil {
return nil, fmt.Errorf("populating details for %s: `model.Properties.PrimaryEndpoints` was nil", accountId)
}
props := *account.Properties
out.IsHnsEnabled = pointer.From(props.IsHnsEnabled)
endpoints := *props.PrimaryEndpoints
if endpoints.Blob != nil {
endpoint := strings.TrimSuffix(*endpoints.Blob, "/")
out.primaryBlobEndpoint = pointer.To(endpoint)
}
if endpoints.Dfs != nil {
endpoint := strings.TrimSuffix(*endpoints.Dfs, "/")
out.primaryDfsEndpoint = pointer.To(endpoint)
}
if endpoints.File != nil {
endpoint := strings.TrimSuffix(*endpoints.File, "/")
out.primaryFileEndpoint = pointer.To(endpoint)
}
if endpoints.Queue != nil {
endpoint := strings.TrimSuffix(*endpoints.Queue, "/")
out.primaryQueueEndpoint = pointer.To(endpoint)
}
if endpoints.Table != nil {
endpoint := strings.TrimSuffix(*endpoints.Table, "/")
out.primaryTableEndpoint = pointer.To(endpoint)
}
return &out, nil
}
// naiveStorageAccountBlobBaseURL naively construct the storage account blob endpoint URL instead of
// learning from the storage account response. This can be incorrect if private dns zone is used.
func naiveStorageAccountBlobBaseURL(e environments.Environment, accountName string) (string, error) {
pDomainSuffix, ok := e.Storage.DomainSuffix()
if !ok {
return "", fmt.Errorf("no storage domain suffix defined for environment: %s", e.Name)
}
return fmt.Sprintf("https://%s.blob.%s", accountName, *pDomainSuffix), nil
}