| // 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 |
| } |