Azure / Azure/azure-dev

Refactor BlobClient into a StorageBlobService following per-call subscription pattern

Open
#7,073 0 comments 1 reaction 2 assignees Assigned to @weikanglim View on GitHub
area/core-cli engineering item
Dominant language
Go
Stars
569
Forks
364
Avg merge
2d 19h
Merged PRs (30d)
136

Description

## Summary

The current `BlobClient` in `cli/azd/pkg/azsdk/storage/` is architecturally unique compared to other Azure service clients in the codebase. It binds the subscription/tenant at **construction time** via `AccountConfig`, whereas all other services (KeyVault, ContainerApps, ContainerRegistry, AppService, etc.) accept `subscriptionId` **per-call** and store only a `SubscriptionCredentialProvider`.

### Current pattern (BlobClient — exception)
```go
// Constructor locks in subscription via AccountConfig
func NewBlobSdkClient(credentialProvider, accountConfig *AccountConfig, ...) (*azblob.Client, error)

// Methods have no subscription parameter
type BlobClient interface {
Download(ctx context.Context, blobPath string) (io.ReadCloser, error)
Upload(ctx context.Context, blobPath string, reader io.Reader) error
// ...
}
```

### Standard pattern (KeyVault, ContainerApps, etc.)
```go
// Constructor takes credential provider only
func NewKeyVaultService(credentialProvider, ...) KeyVaultService

// Methods accept subscriptionId per-call
GetKeyVault(ctx, subscriptionId, resourceGroup, vaultName) (*KeyVault, error)
```

Interestingly, `FileShareService` in the same storage package already follows the standard per-call pattern.

### Proposal

Refactor the blob storage abstraction into a `StorageBlobService` that:
1. Follows the per-call `subscriptionId` pattern used by other Azure services
2. Stores a `SubscriptionCredentialProvider` rather than pre-resolved credentials
3. Can be consumed by the remote state feature (and any future blob storage consumers) without being locked to a single subscription at construction time

This is a code & design improvement — the current implementation works correctly for its single use case (remote state), but consolidating the pattern improves consistency and future extensibility.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.