Skip to content

Commit 7186abd

Browse files
committed
Merge branch 'dev' into dev-feature-sdkmigration
2 parents 5e91d55 + ec1d943 commit 7186abd

55 files changed

Lines changed: 752 additions & 1285 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build/init.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,13 @@ Function Get-BuildTools {
7676
$FileDirectory = Join-Path $NuGetClientRoot $Path
7777
$FilesToMove = Get-ChildItem -Path $FolderUri -File
7878
foreach ($File in $FilesToMove) {
79-
if (-not (Test-Path (Join-Path $FileDirectory $File))) {
80-
$File | Move-Item -Destination $FileDirectory
79+
$DestinationFile = Join-Path $FileDirectory $File.Name
80+
81+
if (-not (Test-Path $DestinationFile)) {
82+
Move-Item -Path $File.FullName -Destination $FileDirectory
8183
}
8284
else {
83-
Write-Host "File '$File' already exists, skipping" -ForegroundColor Blue
85+
Write-Host "File '$($File.Name)' already exists, skipping" -ForegroundColor Blue
8486
}
8587
}
8688

src/NuGet.Jobs.Catalog2Registration/DependencyInjectionExtensions.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,8 @@ public static ContainerBuilder AddCatalog2Registration(this ContainerBuilder con
2828
RegisterCursorStorage(containerBuilder);
2929

3030
containerBuilder
31-
.Register<ICloudBlobClient>(c =>
32-
{
33-
var options = c.Resolve<IOptionsSnapshot<Catalog2RegistrationConfiguration>>();
34-
return new CloudBlobClientWrapper(
35-
options.Value.StorageConnectionString,
36-
requestTimeout: DefaultBlobRequestOptions.ServerTimeout);
37-
});
31+
.RegisterStorageAccount<Catalog2RegistrationConfiguration>(c => c.StorageConnectionString, requestTimeout: DefaultBlobRequestOptions.ServerTimeout)
32+
.As<ICloudBlobClient>();
3833

3934
containerBuilder.Register(c => new Catalog2RegistrationCommand(
4035
c.Resolve<ICollector>(),

src/NuGet.Jobs.Common/JsonConfigurationJob.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ protected virtual void ConfigureDefaultJobServices(IServiceCollection services,
167167
services.Configure<ValidationDbConfiguration>(configurationRoot.GetSection(ValidationDbConfigurationSectionName));
168168
services.Configure<ServiceBusConfiguration>(configurationRoot.GetSection(ServiceBusConfigurationSectionName));
169169
services.Configure<ValidationStorageConfiguration>(configurationRoot.GetSection(ValidationStorageConfigurationSectionName));
170+
services.ConfigureStorageMsi(configurationRoot);
170171

171172
services.AddSingleton(new TelemetryClient(ApplicationInsightsConfiguration.TelemetryConfiguration));
172173
services.AddTransient<ITelemetryClient, TelemetryClientWrapper>();
@@ -197,13 +198,7 @@ private void AddScopedSqlConnectionFactory<TDbConfiguration>(IServiceCollection
197198
public static void ConfigureFeatureFlagAutofacServices(ContainerBuilder containerBuilder)
198199
{
199200
containerBuilder
200-
.Register(c =>
201-
{
202-
var options = c.Resolve<IOptionsSnapshot<FeatureFlagConfiguration>>();
203-
return new CloudBlobClientWrapper(
204-
options.Value.ConnectionString,
205-
requestTimeout: TimeSpan.FromMinutes(2));
206-
})
201+
.RegisterStorageAccount<FeatureFlagConfiguration>(c => c.ConnectionString, requestTimeout: TimeSpan.FromMinutes(2))
207202
.Keyed<ICloudBlobClient>(FeatureFlagBindingKey);
208203

209204
containerBuilder
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Autofac;
6+
using Autofac.Builder;
7+
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.Options;
10+
using NuGet.Services.Configuration;
11+
using NuGetGallery;
12+
13+
namespace NuGet.Jobs
14+
{
15+
public static class StorageAccountHelper
16+
{
17+
public static IServiceCollection ConfigureStorageMsi(
18+
this IServiceCollection serviceCollection,
19+
IConfiguration configuration,
20+
string storageUseManagedIdentityPropertyName = null,
21+
string storageManagedIdentityClientIdPropertyName = null)
22+
{
23+
if (serviceCollection == null)
24+
{
25+
throw new ArgumentNullException(nameof(serviceCollection));
26+
}
27+
if (configuration == null)
28+
{
29+
throw new ArgumentNullException(nameof(configuration));
30+
}
31+
32+
storageUseManagedIdentityPropertyName ??= Constants.StorageUseManagedIdentityPropertyName;
33+
storageManagedIdentityClientIdPropertyName ??= Constants.StorageManagedIdentityClientIdPropertyName;
34+
35+
string useManagedIdentityStr = configuration[storageUseManagedIdentityPropertyName];
36+
bool useManagedIdentity = false;
37+
38+
string managedIdentityClientId = string.IsNullOrWhiteSpace(configuration[storageManagedIdentityClientIdPropertyName])
39+
? configuration[Constants.ManagedIdentityClientIdKey]
40+
: configuration[storageManagedIdentityClientIdPropertyName];
41+
42+
if (!string.IsNullOrWhiteSpace(useManagedIdentityStr))
43+
{
44+
useManagedIdentity = bool.Parse(useManagedIdentityStr);
45+
}
46+
return serviceCollection.Configure<StorageMsiConfiguration>(storageConfiguration =>
47+
{
48+
storageConfiguration.UseManagedIdentity = useManagedIdentity;
49+
storageConfiguration.ManagedIdentityClientId = managedIdentityClientId;
50+
});
51+
}
52+
53+
public static CloudBlobClientWrapper CreateCloudBlobClient(
54+
this IServiceProvider serviceProvider,
55+
string storageConnectionString,
56+
bool readAccessGeoRedundant = false,
57+
TimeSpan? requestTimeout = null)
58+
{
59+
if (serviceProvider == null)
60+
{
61+
throw new ArgumentNullException(nameof(serviceProvider));
62+
}
63+
if (string.IsNullOrWhiteSpace(storageConnectionString))
64+
{
65+
throw new ArgumentException($"{nameof(storageConnectionString)} cannot be null or empty.", nameof(storageConnectionString));
66+
}
67+
68+
var msiConfiguration = serviceProvider.GetRequiredService<IOptions<StorageMsiConfiguration>>().Value;
69+
return CreateCloudBlobClient(
70+
msiConfiguration,
71+
storageConnectionString,
72+
readAccessGeoRedundant,
73+
requestTimeout);
74+
}
75+
76+
public static IRegistrationBuilder<CloudBlobClientWrapper, SimpleActivatorData, SingleRegistrationStyle> RegisterStorageAccount<TConfiguration>(
77+
this ContainerBuilder builder,
78+
Func<TConfiguration, string> getConnectionString,
79+
Func<TConfiguration, bool> getReadAccessGeoRedundant = null,
80+
TimeSpan? requestTimeout = null)
81+
where TConfiguration : class, new()
82+
{
83+
if (builder == null)
84+
{
85+
throw new ArgumentNullException(nameof(builder));
86+
}
87+
if (getConnectionString == null)
88+
{
89+
throw new ArgumentNullException(nameof(getConnectionString));
90+
}
91+
92+
return builder.Register(c =>
93+
{
94+
var options = c.Resolve<IOptionsSnapshot<TConfiguration>>();
95+
string storageConnectionString = getConnectionString(options.Value);
96+
bool readAccessGeoRedundant = getReadAccessGeoRedundant?.Invoke(options.Value) ?? false;
97+
var msiConfiguration = c.Resolve<IOptions<StorageMsiConfiguration>>().Value;
98+
return CreateCloudBlobClient(
99+
msiConfiguration,
100+
storageConnectionString,
101+
readAccessGeoRedundant,
102+
requestTimeout);
103+
});
104+
}
105+
106+
private static CloudBlobClientWrapper CreateCloudBlobClient(
107+
StorageMsiConfiguration msiConfiguration,
108+
string storageConnectionString,
109+
bool readAccessGeoRedundant = false,
110+
TimeSpan? requestTimeout = null)
111+
{
112+
if (msiConfiguration.UseManagedIdentity)
113+
{
114+
if (string.IsNullOrWhiteSpace(msiConfiguration.ManagedIdentityClientId))
115+
{
116+
return CloudBlobClientWrapper.UsingDefaultAzureCredential(
117+
storageConnectionString,
118+
readAccessGeoRedundant: readAccessGeoRedundant,
119+
requestTimeout: requestTimeout);
120+
}
121+
else
122+
{
123+
return CloudBlobClientWrapper.UsingMsi(
124+
storageConnectionString,
125+
msiConfiguration.ManagedIdentityClientId,
126+
readAccessGeoRedundant,
127+
requestTimeout);
128+
}
129+
}
130+
131+
return new CloudBlobClientWrapper(
132+
storageConnectionString,
133+
readAccessGeoRedundant,
134+
requestTimeout);
135+
}
136+
}
137+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace NuGet.Jobs
5+
{
6+
public class StorageMsiConfiguration
7+
{
8+
public bool UseManagedIdentity { get; set; }
9+
public string ManagedIdentityClientId { get; set; }
10+
}
11+
}

src/NuGet.Jobs.GitHubIndexer/Job.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,15 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
4242
services.AddTransient<IRepositoriesCache, DiskRepositoriesCache>();
4343
services.AddTransient<IConfigFileParser, ConfigFileParser>();
4444
services.AddTransient<IRepoFetcher, RepoFetcher>();
45-
services.AddTransient<ICloudBlobClient>(provider => {
46-
var config = provider.GetRequiredService<IOptionsSnapshot<GitHubIndexerConfiguration>>();
47-
return new CloudBlobClientWrapper(config.Value.StorageConnectionString, config.Value.StorageReadAccessGeoRedundant);
48-
});
4945

5046
services.Configure<GitHubIndexerConfiguration>(configurationRoot.GetSection(GitHubIndexerConfigurationSectionName));
5147
}
5248

5349
protected override void ConfigureAutofacServices(ContainerBuilder containerBuilder, IConfigurationRoot configurationRoot)
5450
{
51+
containerBuilder
52+
.RegisterStorageAccount<GitHubIndexerConfiguration>(c => c.StorageConnectionString, c => c.StorageReadAccessGeoRedundant)
53+
.As<ICloudBlobClient>();
5554
}
5655
}
5756
}

src/NuGet.Services.AzureSearch/DependencyInjectionExtensions.cs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using Microsoft.Extensions.Logging;
2020
using Microsoft.Extensions.Options;
2121
using Microsoft.Rest;
22+
using NuGet.Jobs;
2223
using NuGet.Protocol;
2324
using NuGet.Services.AzureSearch.Auxiliary2AzureSearch;
2425
using NuGet.Services.AzureSearch.AuxiliaryFiles;
@@ -108,13 +109,7 @@ private static void RegisterIndexServices(ContainerBuilder containerBuilder, str
108109
private static void RegisterAzureSearchStorageServices(ContainerBuilder containerBuilder, string key)
109110
{
110111
containerBuilder
111-
.Register<ICloudBlobClient>(c =>
112-
{
113-
var options = c.Resolve<IOptionsSnapshot<AzureSearchConfiguration>>();
114-
return new CloudBlobClientWrapper(
115-
options.Value.StorageConnectionString,
116-
requestTimeout: DefaultBlobRequestOptions.ServerTimeout);
117-
})
112+
.RegisterStorageAccount<AzureSearchConfiguration>(c => c.StorageConnectionString, requestTimeout: DefaultBlobRequestOptions.ServerTimeout)
118113
.Keyed<ICloudBlobClient>(key);
119114

120115
containerBuilder
@@ -221,13 +216,9 @@ private static void RegisterAzureSearchStorageServices(ContainerBuilder containe
221216
private static void RegisterAuxiliaryDataStorageServices(ContainerBuilder containerBuilder, string key)
222217
{
223218
containerBuilder
224-
.Register<ICloudBlobClient>(c =>
225-
{
226-
var options = c.Resolve<IOptionsSnapshot<AuxiliaryDataStorageConfiguration>>();
227-
return new CloudBlobClientWrapper(
228-
options.Value.AuxiliaryDataStorageConnectionString,
229-
requestTimeout: DefaultBlobRequestOptions.ServerTimeout);
230-
})
219+
.RegisterStorageAccount<AuxiliaryDataStorageConfiguration>(
220+
c => c.AuxiliaryDataStorageConnectionString,
221+
requestTimeout: DefaultBlobRequestOptions.ServerTimeout)
231222
.Keyed<ICloudBlobClient>(key);
232223

233224
containerBuilder

src/NuGet.Services.Configuration/Constants.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
namespace NuGet.Services.Configuration
@@ -15,5 +15,7 @@ public static class Constants
1515
public static string KeyVaultStoreNameKey = "KeyVault_StoreName";
1616
public static string KeyVaultStoreLocationKey = "KeyVault_StoreLocation";
1717
public static string KeyVaultSendX5c = "KeyVault_SendX5c";
18+
public static string StorageUseManagedIdentityPropertyName = "Storage_UseManagedIdentity";
19+
public static string StorageManagedIdentityClientIdPropertyName = "Storage_ManagedIdentityClientId";
1820
}
1921
}

src/NuGet.Services.Configuration/SecretDictionary.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Collections;
66
using System.Collections.Generic;
77
using System.Linq;
8-
using System.Threading.Tasks;
98
using NuGet.Services.KeyVault;
109

1110
namespace NuGet.Services.Configuration
@@ -122,14 +121,9 @@ private string InjectOrSkip(string key, string value)
122121
{
123122
if (!_notInjectedKeys.Contains(key))
124123
{
125-
return Inject(value).Result;
124+
return _secretInjector.Inject(value);
126125
}
127126
return value;
128127
}
129-
130-
private Task<string> Inject(string value)
131-
{
132-
return _secretInjector.InjectAsync(value);
133-
}
134128
}
135129
}

0 commit comments

Comments
 (0)