From 592a597c0490610438f7f3e66fbff17a474b7183 Mon Sep 17 00:00:00 2001
From: giventocode <3589801+giventocode@users.noreply.github.com>
Date: Mon, 6 Feb 2023 13:26:22 -0500
Subject: [PATCH] lookup does not occur in production, refactoring,
---
.../ArmResourceInformationFinder.cs | 77 +++++++++++++++++++
.../AzureManagementClientsFactory.cs | 31 --------
.../Configuration/BatchAccountOptions.cs | 2 +-
.../Configuration/ContainerRegistryOptions.cs | 2 +-
.../Configuration/RetryPolicyOptions.cs | 2 +-
.../Management/Configuration/TerraOptions.cs | 2 +-
src/TesApi.Web/Startup.cs | 61 ++++++++-------
7 files changed, 114 insertions(+), 63 deletions(-)
create mode 100644 src/TesApi.Web/Management/ArmResourceInformationFinder.cs
diff --git a/src/TesApi.Web/Management/ArmResourceInformationFinder.cs b/src/TesApi.Web/Management/ArmResourceInformationFinder.cs
new file mode 100644
index 000000000..740c2eb0a
--- /dev/null
+++ b/src/TesApi.Web/Management/ArmResourceInformationFinder.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Azure.Management.ApplicationInsights.Management;
+using Microsoft.Azure.Management.Batch;
+using Microsoft.Azure.Services.AppAuthentication;
+using Microsoft.Rest;
+
+namespace TesApi.Web.Management
+{
+ ///
+ /// Provides utility methods to find resource information using the TES service identity
+ ///
+ public class ArmResourceInformationFinder
+ {
+ ///
+ /// Looks up the AppInsights instrumentation key in subscriptions the TES services has access to
+ ///
+ ///
+ ///
+ public static async Task GetAppInsightsInstrumentationKeyAsync(string accountName)
+ {
+ var azureClient = await AzureManagementClientsFactory.GetAzureManagementClientAsync();
+ var subscriptionIds = (await azureClient.Subscriptions.ListAsync()).Select(s => s.SubscriptionId);
+
+ var credentials = new TokenCredentials(await GetAzureAccessTokenAsync());
+
+ foreach (var subscriptionId in subscriptionIds)
+ {
+ var app = (await new ApplicationInsightsManagementClient(credentials) { SubscriptionId = subscriptionId }.Components.ListAsync())
+ .FirstOrDefault(a => a.ApplicationId.Equals(accountName, StringComparison.OrdinalIgnoreCase));
+
+ if (app is not null)
+ {
+ return app.InstrumentationKey;
+ }
+ }
+
+ return null;
+ }
+ //TODO: refactor this to use Azure Identity token provider.
+ private static Task GetAzureAccessTokenAsync(string resource = "https://management.azure.com/")
+ {
+ return new AzureServiceTokenProvider().GetAccessTokenAsync(resource);
+ }
+
+ ///
+ /// Attempts to get the batch resource information using the ARM api.
+ /// Returns null if the resource was not found or the account does not have access.
+ ///
+ /// batch account name
+ ///
+ public static async Task TryGetResourceInformationFromAccountNameAsync(string batchAccountName)
+ {
+ //TODO: look if a newer version of the management SDK provides a simpler way to look for this information .
+ var tokenCredentials = new TokenCredentials(await GetAzureAccessTokenAsync());
+ var azureClient = await AzureManagementClientsFactory.GetAzureManagementClientAsync();
+
+ var subscriptionIds = (await azureClient.Subscriptions.ListAsync()).Select(s => s.SubscriptionId);
+
+ foreach (var subId in subscriptionIds)
+ {
+ using var batchClient = new BatchManagementClient(tokenCredentials) { SubscriptionId = subId };
+
+ var batchAccount = (await batchClient.BatchAccount.ListAsync())
+ .FirstOrDefault(a => a.Name.Equals(batchAccountName, StringComparison.OrdinalIgnoreCase));
+
+ if (batchAccount is not null)
+ {
+ return BatchAccountResourceInformation.FromBatchResourceId(batchAccount.Id, batchAccount.Location);
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/TesApi.Web/Management/AzureManagementClientsFactory.cs b/src/TesApi.Web/Management/AzureManagementClientsFactory.cs
index f64a43bc4..4a98582cb 100644
--- a/src/TesApi.Web/Management/AzureManagementClientsFactory.cs
+++ b/src/TesApi.Web/Management/AzureManagementClientsFactory.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT License.
using System;
-using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Management.Batch;
using Microsoft.Azure.Management.ResourceManager.Fluent;
@@ -71,36 +70,6 @@ public async Task CreateBatchAccountManagementClient()
public async Task CreateAzureManagementClientAsync()
=> await AzureManagementClientsFactory.GetAzureManagementClientAsync();
- ///
- /// Attempts to get the batch resource information using the ARM api.
- /// Returns null if the resource was not found or the account does not have access.
- ///
- /// batch account name
- ///
- public static async Task TryGetResourceInformationFromAccountNameAsync(string batchAccountName)
- {
- //TODO: look if a newer version of the management SDK provides a simpler way to look for this information .
- var tokenCredentials = new TokenCredentials(await GetAzureAccessTokenAsync());
- var azureClient = await GetAzureManagementClientAsync();
-
- var subscriptionIds = (await azureClient.Subscriptions.ListAsync()).Select(s => s.SubscriptionId);
-
- foreach (var subId in subscriptionIds)
- {
- using var batchClient = new BatchManagementClient(tokenCredentials) { SubscriptionId = subId };
-
- var batchAccount = (await batchClient.BatchAccount.ListAsync())
- .FirstOrDefault(a => a.Name.Equals(batchAccountName, StringComparison.OrdinalIgnoreCase));
-
- if (batchAccount is not null)
- {
- return BatchAccountResourceInformation.FromBatchResourceId(batchAccount.Id, batchAccount.Location);
- }
- }
-
- return null;
- }
-
///
/// Creates a new instance of Azure Management client
///
diff --git a/src/TesApi.Web/Management/Configuration/BatchAccountOptions.cs b/src/TesApi.Web/Management/Configuration/BatchAccountOptions.cs
index 10eb04178..5350f8ab3 100644
--- a/src/TesApi.Web/Management/Configuration/BatchAccountOptions.cs
+++ b/src/TesApi.Web/Management/Configuration/BatchAccountOptions.cs
@@ -11,7 +11,7 @@ public class BatchAccountOptions
///
/// Configuration section.
///
- public const string BatchAccount = "BatchAccount";
+ public const string SectionName = "BatchAccount";
///
/// Default Azure offer durable id.
///
diff --git a/src/TesApi.Web/Management/Configuration/ContainerRegistryOptions.cs b/src/TesApi.Web/Management/Configuration/ContainerRegistryOptions.cs
index e51d0a7e5..feb997ba0 100644
--- a/src/TesApi.Web/Management/Configuration/ContainerRegistryOptions.cs
+++ b/src/TesApi.Web/Management/Configuration/ContainerRegistryOptions.cs
@@ -11,7 +11,7 @@ public class ContainerRegistryOptions
///
/// Configuration section.
///
- public const string ContainerRegistrySection = "ContainerRegistry";
+ public const string SectionName = "ContainerRegistry";
///
/// Enables/disables auto-discovery features
///
diff --git a/src/TesApi.Web/Management/Configuration/RetryPolicyOptions.cs b/src/TesApi.Web/Management/Configuration/RetryPolicyOptions.cs
index 2fdfc3a89..5774fa6b8 100644
--- a/src/TesApi.Web/Management/Configuration/RetryPolicyOptions.cs
+++ b/src/TesApi.Web/Management/Configuration/RetryPolicyOptions.cs
@@ -11,7 +11,7 @@ public class RetryPolicyOptions
///
/// Retry policy configuration section
///
- public const string RetryPolicy = "RetryPolicy";
+ public const string SectionName = "RetryPolicy";
private const int DefaultRetryCount = 3;
private const int DefaultExponentialBackOffExponent = 2;
diff --git a/src/TesApi.Web/Management/Configuration/TerraOptions.cs b/src/TesApi.Web/Management/Configuration/TerraOptions.cs
index 07d0b9d59..f209b8d77 100644
--- a/src/TesApi.Web/Management/Configuration/TerraOptions.cs
+++ b/src/TesApi.Web/Management/Configuration/TerraOptions.cs
@@ -11,7 +11,7 @@ public class TerraOptions
///
/// Terra configuration section
///
- public const string Terra = "Terra";
+ public const string SectionName = "Terra";
private const int DefaultSasTokenExpirationInSeconds = 60 * 24 * 3; // 3 days
///
diff --git a/src/TesApi.Web/Startup.cs b/src/TesApi.Web/Startup.cs
index 654900629..8d73d1596 100644
--- a/src/TesApi.Web/Startup.cs
+++ b/src/TesApi.Web/Startup.cs
@@ -59,16 +59,18 @@ public Startup(IConfiguration configuration, ILogger logger, IWebHostEn
///
/// The Microsoft.Extensions.DependencyInjection.IServiceCollection to add the services to.
public void ConfigureServices(IServiceCollection services)
- => services
- .Configure(Configuration.GetSection(BatchAccountOptions.BatchAccount))
+ {
+ services
+ .Configure(Configuration.GetSection(BatchAccountOptions.SectionName))
.Configure(Configuration.GetSection(CosmosDbOptions.CosmosDbAccount))
- .Configure(Configuration.GetSection(RetryPolicyOptions.RetryPolicy))
- .Configure(Configuration.GetSection(TerraOptions.Terra))
+ .Configure(Configuration.GetSection(RetryPolicyOptions.SectionName))
+ .Configure(Configuration.GetSection(TerraOptions.SectionName))
.AddSingleton()
.AddSingleton()
- .AddSingleton(sp => ActivatorUtilities.CreateInstance(sp, (IAzureProxy)sp.GetRequiredService(typeof(AzureProxy))))
-
+ .AddSingleton(sp =>
+ ActivatorUtilities.CreateInstance(sp,
+ (IAzureProxy)sp.GetRequiredService(typeof(AzureProxy))))
.AddSingleton(CreateCosmosDbRepositoryFromConfiguration)
.AddSingleton()
.AddTransient()
@@ -93,7 +95,6 @@ public void ConfigureServices(IServiceCollection services)
.AddSingleton(CreateBatchAccountResourceInformation)
.AddSingleton(CreateBatchQuotaProviderFromConfiguration)
.AddSingleton()
- .AddSingleton() //added so config utils gets the arm implementation, to be removed once config utils is refactored.
.AddSingleton()
.AddSingleton(s => new DefaultAzureCredential())
@@ -127,29 +128,33 @@ public void ConfigureServices(IServiceCollection services)
.AddHostedService()
.AddHostedService()
.AddHostedService()
- .AddHostedService()
- //.AddHostedService()
+ .AddHostedService();
+ //.AddHostedService()
- //Configure AppInsights Azure Service when in PRODUCTION environment
- .IfThenElse(hostingEnvironment.IsProduction(),
- s =>
- {
- var applicationInsightsAccountName = Configuration["ApplicationInsightsAccountName"];
- var instrumentationKey = AzureProxy.GetAppInsightsInstrumentationKeyAsync(applicationInsightsAccountName).Result;
+ AddAppInsightsWithDefaultOrLookingUpTheConnectionString(services);
+ }
- if (instrumentationKey is not null)
- {
- var connectionString = $"InstrumentationKey={instrumentationKey}";
- return s.AddApplicationInsightsTelemetry(options =>
- {
- options.ConnectionString = connectionString;
- });
- }
-
- return s;
- },
- s => s.AddApplicationInsightsTelemetry());
+ private void AddAppInsightsWithDefaultOrLookingUpTheConnectionString(IServiceCollection services)
+ {
+ var accountName = Configuration["ApplicationInsightsAccountName"];
+
+ if (string.IsNullOrEmpty(accountName))
+ {
+ //use default settings that will use the app insights configuration
+ services.AddApplicationInsightsTelemetry();
+ return;
+ }
+
+ services.AddApplicationInsightsTelemetry(s =>
+ {
+ var instrumentationKey = ArmResourceInformationFinder
+ .GetAppInsightsInstrumentationKeyAsync(accountName)
+ .Result;
+
+ s.ConnectionString = $"InstrumentationKey={instrumentationKey}";
+ });
+ }
private IBatchQuotaProvider CreateBatchQuotaProviderFromConfiguration(IServiceProvider services)
{
@@ -227,7 +232,7 @@ private BatchAccountResourceInformation CreateBatchAccountResourceInformation(IS
if (string.IsNullOrWhiteSpace(options.Value.AppKey))
{
//we are assuming Arm with MI/RBAC if no key is provided. Try to get info from the batch account.
- var task = AzureManagementClientsFactory.TryGetResourceInformationFromAccountNameAsync(options.Value.AccountName);
+ var task = ArmResourceInformationFinder.TryGetResourceInformationFromAccountNameAsync(options.Value.AccountName);
task.Wait();
if (task.Result == null)