// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Azure;
using Azure.Containers.ContainerRegistry;
using Azure.ResourceManager.ContainerRegistry;
using AzureMcp.Core.Services.Azure;
using AzureMcp.Core.Services.Azure.Subscription;
using AzureMcp.Core.Services.Azure.Tenant;
namespace AzureMcp.Acr.Services;
public sealed class AcrService(ISubscriptionService subscriptionService, ITenantService tenantService) : BaseAzureService(tenantService), IAcrService
{
private readonly ISubscriptionService _subscriptionService = subscriptionService ?? throw new ArgumentNullException(nameof(subscriptionService));
public async Task<List<Models.AcrRegistryInfo>> ListRegistries(
string subscription,
string? resourceGroup = null,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(subscription);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);
var registries = new List<Models.AcrRegistryInfo>();
// Select enumeration source based on optional resource group
if (!string.IsNullOrWhiteSpace(resourceGroup))
{
var resourceGroupResource = await subscriptionResource.GetResourceGroupAsync(resourceGroup);
await foreach (var registry in resourceGroupResource.Value.GetContainerRegistries().GetAllAsync())
{
AddProjectionIfValid(registries, registry);
}
}
else
{
await foreach (var registry in subscriptionResource.GetContainerRegistriesAsync())
{
AddProjectionIfValid(registries, registry);
}
}
return registries;
}
private static void AddProjectionIfValid(List<Models.AcrRegistryInfo> list, ContainerRegistryResource? registry)
{
var data = registry?.Data;
if (data?.Name is null)
{
return;
}
list.Add(new Models.AcrRegistryInfo(
data.Name,
data.Location,
data.LoginServer,
data.Sku?.Name.ToString(),
data.Sku?.Tier?.ToString()));
}
public async Task<Dictionary<string, List<string>>> ListRegistryRepositories(
string subscription,
string? resourceGroup = null,
string? registry = null,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(subscription);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);
var result = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
async Task AddRepositoriesForRegistryAsync(ContainerRegistryResource reg)
{
var data = reg.Data;
if (data?.LoginServer is null || string.IsNullOrWhiteSpace(data.Name))
{
return;
}
// Build data-plane client for this login server
var credential = await GetCredential(tenant);
var options = ConfigureRetryPolicy(AddDefaultPolicies(new ContainerRegistryClientOptions()), retryPolicy);
var acrEndpoint = new Uri($"https://{data.LoginServer}");
var client = new ContainerRegistryClient(acrEndpoint, credential, options);
var repoNames = new List<string>();
try
{
await foreach (var repo in client.GetRepositoryNamesAsync())
{
if (!string.IsNullOrWhiteSpace(repo))
{
repoNames.Add(repo);
}
}
}
catch (RequestFailedException)
{
// If we cannot enumerate repositories (e.g., permissions), return empty list for that registry
}
result[data.Name] = repoNames;
}
if (!string.IsNullOrWhiteSpace(registry))
{
// Fetch a single registry by name, optionally within the provided resource group
if (!string.IsNullOrWhiteSpace(resourceGroup))
{
var rg = await subscriptionResource.GetResourceGroupAsync(resourceGroup);
var regRes = await rg.Value.GetContainerRegistries().GetAsync(registry);
await AddRepositoriesForRegistryAsync(regRes.Value);
}
else
{
// enumerate across subscription to find the registry name
await foreach (var regRes in subscriptionResource.GetContainerRegistriesAsync())
{
if (string.Equals(regRes.Data?.Name, registry, StringComparison.OrdinalIgnoreCase))
{
await AddRepositoriesForRegistryAsync(regRes);
break;
}
}
}
}
else if (!string.IsNullOrWhiteSpace(resourceGroup))
{
var rg = await subscriptionResource.GetResourceGroupAsync(resourceGroup);
await foreach (var regRes in rg.Value.GetContainerRegistries().GetAllAsync())
{
await AddRepositoriesForRegistryAsync(regRes);
}
}
else
{
await foreach (var regRes in subscriptionResource.GetContainerRegistriesAsync())
{
await AddRepositoriesForRegistryAsync(regRes);
}
}
return result;
}
}