Skip to content

Commit

Permalink
feat: Adding ability to define a custom AzureEnvironment. (#2579)
Browse files Browse the repository at this point in the history
* custom cloud support - addressing review comments

* coderefactor

* remove unused declaratives

* Add unit test + address review comments

* refactor

* add interface for cloud + endpoints

* refactor from codefactor comment

* cleanup

* Add Log Analytics Endpoint for Custom Cloud

* add unit test + fix code quality failure

* code factor

* code quality fix

---------

Co-authored-by: Suraiya Hameed <[email protected]>
  • Loading branch information
kevand900 and Suraiya-Hameed authored Feb 12, 2025
1 parent 22b0792 commit 2778e84
Show file tree
Hide file tree
Showing 31 changed files with 1,129 additions and 259 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System.Collections.Generic;
using Promitor.Core.Configuration;
using Promitor.Core.Extensions;
using Promitor.Core.Serialization.Enum;

namespace Promitor.Agents.ResourceDiscovery.Configuration
{
public class AzureLandscape
public class AzureLandscape : IAzureCloudEndpoints
{
public string TenantId { get; set; }
public List<string> Subscriptions { get; set; }
public AzureCloud Cloud { get; set; } = AzureCloud.Global;
public AzureEndpoints Endpoints { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ private async Task OpenConnectionAsync()

private async Task<ResourceGraphClient> CreateClientAsync()
{
var azureEnvironment = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureEnvironment();
var azureAuthorityHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.Cloud.GetAzureAuthorityHost();
var azureEnvironment = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.GetAzureEnvironment();
var azureAuthorityHost = _resourceDeclarationMonitor.CurrentValue.AzureLandscape.GetAzureAuthorityHost();

var credentials = await AzureAuthenticationFactory.GetTokenCredentialsAsync(azureEnvironment.ManagementEndpoint, TenantId, _azureAuthenticationInfo, azureAuthorityHost);
var resourceManagerBaseUri = new Uri(azureEnvironment.ResourceManagerEndpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ public ValidationResult Run()
{
errorMessages.Add("No Azure cloud was configured");
}

if (_azureLandscape.Subscriptions == null || _azureLandscape.Subscriptions.Any() == false)

if (_azureLandscape.Cloud == AzureCloud.Custom)
{
errorMessages.AddRange(ValidateCustomCloud());
}

if (_azureLandscape.Subscriptions == null || _azureLandscape.Subscriptions.Count == 0)
{
errorMessages.Add("No subscription id(s) were configured to query");
}
Expand All @@ -54,5 +59,44 @@ public ValidationResult Run()

return errorMessages.Any() ? ValidationResult.Failure(ComponentName, errorMessages) : ValidationResult.Successful(ComponentName);
}

private IEnumerable<string> ValidateCustomCloud()
{
var errorMessages = new List<string>();

if(_azureLandscape.Endpoints == null)
{
errorMessages.Add("Endpoints are not configured for Azure Custom cloud");
}
else
{
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.AuthenticationEndpoint))
{
errorMessages.Add("Azure Custom cloud authentication endpoint was not configured to query");
}
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.ResourceManagerEndpoint))
{
errorMessages.Add("Azure Custom cloud resource management endpoint was not configured to query");
}
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.ManagementEndpoint))
{
errorMessages.Add("Azure Custom cloud service management endpoint was not configured to query");
}
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.GraphEndpoint))
{
errorMessages.Add("Azure Custom cloud graph endpoint was not configured to query");
}
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.StorageEndpointSuffix))
{
errorMessages.Add("Azure Custom cloud storage service url suffix was not configured to query");
}
if (string.IsNullOrWhiteSpace(_azureLandscape.Endpoints.KeyVaultSuffix))
{
errorMessages.Add("Azure Custom cloud Key Vault service url suffix was not configured to query");
}
}

return errorMessages;
}
}
}
24 changes: 13 additions & 11 deletions src/Promitor.Agents.Scraper/AzureMonitorClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using Promitor.Core.Extensions;
using Promitor.Core.Metrics.Interfaces;
using Promitor.Core.Metrics.Sinks;
using Promitor.Core.Serialization.Enum;
using Promitor.Core.Scraping.Configuration.Model;
using Promitor.Integrations.Azure.Authentication;
using Promitor.Integrations.AzureMonitor;
using Promitor.Integrations.AzureMonitor.Configuration;
Expand All @@ -21,7 +21,7 @@ public class AzureMonitorClientFactory
/// <summary>
/// Provides an Azure Monitor client
/// </summary>
/// <param name="cloud">Name of the Azure cloud to interact with</param>
/// <param name="azureMetadata">Azure metadata information</param>
/// <param name="tenantId">Id of the tenant that owns the Azure subscription</param>
/// <param name="subscriptionId">Id of the Azure subscription</param>
/// <param name="metricSinkWriter">Writer to send metrics to all configured sinks</param>
Expand All @@ -31,19 +31,21 @@ public class AzureMonitorClientFactory
/// <param name="azureMonitorIntegrationConfiguration">Options for Azure Monitor integration</param>
/// <param name="azureMonitorLoggingConfiguration">Options for Azure Monitor logging</param>
/// <param name="loggerFactory">Factory to create loggers with</param>
public IAzureMonitorClient CreateIfNotExists(AzureCloud cloud, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingSystemMetricsPublisher azureScrapingSystemMetricsPublisher, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions<AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions<AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory)
{
public IAzureMonitorClient CreateIfNotExists(AzureMetadata azureMetadata, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingSystemMetricsPublisher azureScrapingSystemMetricsPublisher, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions<AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions<AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory)
{
if (_azureMonitorClients.TryGetValue(subscriptionId, out var value))
{
return value;
}

var useAzureMonitorSdk = azureMonitorIntegrationConfiguration.Value.UseAzureMonitorSdk;
IAzureMonitorClient azureMonitorClient;
if (useAzureMonitorSdk) {
azureMonitorClient = CreateNewAzureMonitorQueryClient(cloud, tenantId, subscriptionId, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory);
} else {
azureMonitorClient = CreateNewLegacyAzureMonitorClient(cloud.GetAzureEnvironment(), tenantId, subscriptionId, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory);
if (useAzureMonitorSdk)
{
azureMonitorClient = CreateNewAzureMonitorQueryClient(azureMetadata, tenantId, subscriptionId, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory);
}
else
{
azureMonitorClient = CreateNewLegacyAzureMonitorClient(azureMetadata.GetAzureEnvironment(), tenantId, subscriptionId, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory);
}
_azureMonitorClients.TryAdd(subscriptionId, azureMonitorClient);

Expand All @@ -57,10 +59,10 @@ private static LegacyAzureMonitorClient CreateNewLegacyAzureMonitorClient(AzureE
return azureMonitorClientLegacy;
}

private static AzureMonitorQueryClient CreateNewAzureMonitorQueryClient(AzureCloud cloud, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingSystemMetricsPublisher azureScrapingSystemMetricsPublisher, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions<AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions<AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory)
private static AzureMonitorQueryClient CreateNewAzureMonitorQueryClient(AzureMetadata azureMetadata, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingSystemMetricsPublisher azureScrapingSystemMetricsPublisher, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions<AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions<AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory)
{
var azureCredentials = AzureAuthenticationFactory.GetConfiguredAzureAuthentication(configuration);
var azureMonitorQueryClient = new AzureMonitorQueryClient(cloud, tenantId, subscriptionId, azureCredentials, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, loggerFactory, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration);
var azureMonitorQueryClient = new AzureMonitorQueryClient(azureMetadata, tenantId, subscriptionId, azureCredentials, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, loggerFactory, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration);
return azureMonitorQueryClient;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Promitor.Agents.Scraper/Docs/Open-Api.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public static IServiceCollection DefineDependencies(this IServiceCollection serv

services.AddSingleton<IDeserializer<MetricsDeclarationV1>, V1Deserializer>();
services.AddSingleton<IDeserializer<AzureMetadataV1>, AzureMetadataDeserializer>();
services.AddSingleton<IDeserializer<AzureEndpointsV1>, AzureEndpointsDeserializer>();
services.AddSingleton<IDeserializer<MetricDefaultsV1>, MetricDefaultsDeserializer>();
services.AddSingleton<IDeserializer<MetricDefinitionV1>, MetricDefinitionDeserializer>();
services.AddSingleton<IDeserializer<AggregationV1>, AggregationDeserializer>();
Expand Down
18 changes: 9 additions & 9 deletions src/Promitor.Agents.Scraper/Scheduling/ResourcesScrapingJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,14 @@ private async Task ScrapeMetricBatched(BatchScrapeDefinition<IAzureResourceDefin
try
{
var resourceSubscriptionId = batchScrapeDefinition.ScrapeDefinitionBatchProperties.SubscriptionId;
var azureMonitorClient = _azureMonitorClientFactory.CreateIfNotExists(_metricsDeclaration.AzureMetadata.Cloud, _metricsDeclaration.AzureMetadata.TenantId,
var azureMonitorClient = _azureMonitorClientFactory.CreateIfNotExists(_metricsDeclaration.AzureMetadata, _metricsDeclaration.AzureMetadata.TenantId,
resourceSubscriptionId, _metricSinkWriter, _azureScrapingSystemMetricsPublisher, _resourceMetricDefinitionMemoryCache, _configuration,
_azureMonitorIntegrationConfiguration, _azureMonitorLoggingConfiguration, _loggerFactory);
var azureEnvironent = _metricsDeclaration.AzureMetadata.Cloud.GetAzureEnvironment();
var azureEnvironment = _metricsDeclaration.AzureMetadata.GetAzureEnvironment();

var tokenCredential = AzureAuthenticationFactory.GetTokenCredential(azureEnvironent.ManagementEndpoint, _metricsDeclaration.AzureMetadata.TenantId,
AzureAuthenticationFactory.GetConfiguredAzureAuthentication(_configuration), new Uri(_metricsDeclaration.AzureMetadata.Cloud.GetAzureEnvironment().AuthenticationEndpoint));
var logAnalyticsClient = new LogAnalyticsClient(_loggerFactory, azureEnvironent, tokenCredential);
var tokenCredential = AzureAuthenticationFactory.GetTokenCredential(azureEnvironment.ManagementEndpoint, _metricsDeclaration.AzureMetadata.TenantId,
AzureAuthenticationFactory.GetConfiguredAzureAuthentication(_configuration), new Uri (_metricsDeclaration.AzureMetadata.GetAzureEnvironment().AuthenticationEndpoint));
var logAnalyticsClient = new LogAnalyticsClient(_loggerFactory, _metricsDeclaration.AzureMetadata.GetLogAnalyticsEndpoint(), tokenCredential);

var scraper = _metricScraperFactory.CreateScraper(batchScrapeDefinition.ScrapeDefinitionBatchProperties.ResourceType, _metricSinkWriter, _azureScrapingSystemMetricsPublisher, azureMonitorClient, logAnalyticsClient);

Expand All @@ -313,15 +313,15 @@ private async Task ScrapeMetric(ScrapeDefinition<IAzureResourceDefinition> scrap
var resourceSubscriptionId = !string.IsNullOrWhiteSpace(scrapeDefinition.Resource.SubscriptionId)
? scrapeDefinition.Resource.SubscriptionId
: _metricsDeclaration.AzureMetadata.SubscriptionId;
var azureEnvironent = _metricsDeclaration.AzureMetadata.Cloud.GetAzureEnvironment();
var azureEnvironent = _metricsDeclaration.AzureMetadata.GetAzureEnvironment();
Logger.LogInformation("Parsed SDK Config {UseAzureMonitorSdk}", _azureMonitorIntegrationConfiguration.Value.UseAzureMonitorSdk);
var azureMonitorClient = _azureMonitorClientFactory.CreateIfNotExists(_metricsDeclaration.AzureMetadata.Cloud, _metricsDeclaration.AzureMetadata.TenantId,
var azureMonitorClient = _azureMonitorClientFactory.CreateIfNotExists(_metricsDeclaration.AzureMetadata, _metricsDeclaration.AzureMetadata.TenantId,
resourceSubscriptionId, _metricSinkWriter, _azureScrapingSystemMetricsPublisher, _resourceMetricDefinitionMemoryCache, _configuration,
_azureMonitorIntegrationConfiguration, _azureMonitorLoggingConfiguration, _loggerFactory);

var tokenCredential = AzureAuthenticationFactory.GetTokenCredential(azureEnvironent.ManagementEndpoint, _metricsDeclaration.AzureMetadata.TenantId,
AzureAuthenticationFactory.GetConfiguredAzureAuthentication(_configuration), new Uri(_metricsDeclaration.AzureMetadata.Cloud.GetAzureEnvironment().AuthenticationEndpoint));
var logAnalyticsClient = new LogAnalyticsClient(_loggerFactory, azureEnvironent, tokenCredential);
AzureAuthenticationFactory.GetConfiguredAzureAuthentication(_configuration), new Uri(_metricsDeclaration.AzureMetadata.GetAzureEnvironment().AuthenticationEndpoint));
var logAnalyticsClient = new LogAnalyticsClient(_loggerFactory, _metricsDeclaration.AzureMetadata.GetLogAnalyticsEndpoint(), tokenCredential);

var scraper = _metricScraperFactory.CreateScraper(scrapeDefinition.Resource.ResourceType, _metricSinkWriter, _azureScrapingSystemMetricsPublisher, azureMonitorClient, logAnalyticsClient);

Expand Down
Loading

0 comments on commit 2778e84

Please sign in to comment.