Skip to content

Commit

Permalink
Merge pull request #8514 from NuGet/dev
Browse files Browse the repository at this point in the history
[ReleasePrep][2021.04.08]RI dev into main
  • Loading branch information
ryuyu committed Apr 9, 2021
2 parents be38792 + 3fcfd71 commit c71e124
Show file tree
Hide file tree
Showing 36 changed files with 707 additions and 259 deletions.
4 changes: 4 additions & 0 deletions src/Bootstrap/dist/css/bootstrap-theme.css

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

15 changes: 10 additions & 5 deletions src/Bootstrap/less/theme/page-add-organization.less
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
.page-add-organization {
.owner-image {
margin-top: 6px;
margin-bottom: 6px;
}
}
.owner-image {
margin-top: 6px;
margin-bottom: 6px;
}

.required:after {
color: red;
content: " *";
}
}
6 changes: 3 additions & 3 deletions src/Bootstrap/package-lock.json

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

2 changes: 1 addition & 1 deletion src/DatabaseMigrationTools/DatabaseMigrationTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NuGet.Services.Validation">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<Version>4.3.0-dev-3612825</Version>
</PackageReference>
<PackageReference Include="NuGet.Services.Cursor">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
Expand Down
13 changes: 12 additions & 1 deletion src/NuGet.Services.Entities/Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace NuGet.Services.Entities
public class Package
: IPackageEntity
{
private string _id;

#pragma warning disable 618 // TODO: remove Package.Authors completely once production services definitely no longer need it
public Package()
Expand Down Expand Up @@ -264,7 +265,17 @@ public bool HasEmbeddedReadme

public virtual ICollection<SymbolPackage> SymbolPackages { get; set; }

public string Id => PackageRegistration.Id;
/// <summary>
/// The package ID with casing specific to this version if available, otherwise it will fallback to the ID on
/// the package registration. WARNING: this property should not be used for comparisons in LINQ to SQL because
/// it may be null sometimes. Use <see cref="PackageRegistration.Id"/> instead.
/// </summary>
[StringLength(Constants.MaxPackageIdLength)]
public string Id
{
get => _id ?? PackageRegistration?.Id;
set => _id = value;
}

public EmbeddedLicenseFileType EmbeddedLicenseType { get; set; }

Expand Down
41 changes: 14 additions & 27 deletions src/NuGetGallery.Core/Auditing/CloudAuditingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ public class CloudAuditingService : AuditingService, ICloudStorageStatusDependen
{
public static readonly string DefaultContainerName = "auditing";

private CloudBlobContainer _auditContainer;
private Func<ICloudBlobContainer> _auditContainerFactory;
private Func<Task<AuditActor>> _getOnBehalfOf;

public CloudAuditingService(string storageConnectionString, bool readAccessGeoRedundant, Func<Task<AuditActor>> getOnBehalfOf)
: this(GetContainer(storageConnectionString, readAccessGeoRedundant), getOnBehalfOf)
public CloudAuditingService(Func<ICloudBlobClient> cloudBlobClientFactory, Func<Task<AuditActor>> getOnBehalfOf)
: this(() => GetContainer(cloudBlobClientFactory), getOnBehalfOf)
{
}

public CloudAuditingService(CloudBlobContainer auditContainer, Func<Task<AuditActor>> getOnBehalfOf)
public CloudAuditingService(Func<ICloudBlobContainer> auditContainerFactory, Func<Task<AuditActor>> getOnBehalfOf)
{
_auditContainer = auditContainer;
_auditContainerFactory = auditContainerFactory;
_getOnBehalfOf = getOnBehalfOf;
}

Expand All @@ -52,7 +52,8 @@ protected override async Task SaveAuditRecordAsync(string auditData, string reso
$"{filePath.Replace(Path.DirectorySeparatorChar, '/')}/" +
$"{Guid.NewGuid().ToString("N")}-{action.ToLowerInvariant()}.audit.v1.json";

var blob = _auditContainer.GetBlockBlobReference(fullPath);
var container = _auditContainerFactory();
var blob = container.GetBlobReference(fullPath);
bool retry = false;
try
{
Expand All @@ -74,37 +75,23 @@ protected override async Task SaveAuditRecordAsync(string auditData, string reso
{
// Create the container and try again,
// this time we let exceptions bubble out
await Task.Factory.FromAsync(
(cb, s) => _auditContainer.BeginCreateIfNotExists(cb, s),
ar => _auditContainer.EndCreateIfNotExists(ar),
null);
await container.CreateIfNotExistAsync(permissions: null);
await WriteBlob(auditData, fullPath, blob);
}
}

private static CloudBlobContainer GetContainer(string storageConnectionString, bool readAccessGeoRedundant)
private static ICloudBlobContainer GetContainer(Func<ICloudBlobClient> cloudBlobClientFactory)
{
var cloudBlobClient = CloudStorageAccount.Parse(storageConnectionString).CreateCloudBlobClient();
if (readAccessGeoRedundant)
{
cloudBlobClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
}
var cloudBlobClient = cloudBlobClientFactory();
return cloudBlobClient.GetContainerReference(DefaultContainerName);
}

private static async Task WriteBlob(string auditData, string fullPath, CloudBlockBlob blob)
private static async Task WriteBlob(string auditData, string fullPath, ISimpleCloudBlob blob)
{
try
{
var strm = await Task.Factory.FromAsync(
(cb, s) => blob.BeginOpenWrite(
AccessCondition.GenerateIfNoneMatchCondition("*"),
new BlobRequestOptions(),
new OperationContext(),
cb, s),
ar => blob.EndOpenWrite(ar),
null);
using (var writer = new StreamWriter(strm))
using (var stream = await blob.OpenWriteAsync(AccessCondition.GenerateIfNoneMatchCondition("*")))
using (var writer = new StreamWriter(stream))
{
await writer.WriteAsync(auditData);
}
Expand All @@ -125,7 +112,7 @@ private static async Task WriteBlob(string auditData, string fullPath, CloudBloc

public Task<bool> IsAvailableAsync(BlobRequestOptions options, OperationContext operationContext)
{
return _auditContainer.ExistsAsync(options, operationContext);
return _auditContainerFactory().ExistsAsync(options, operationContext);
}

public override string RenderAuditEntry(AuditEntry entry)
Expand Down
59 changes: 39 additions & 20 deletions src/NuGetGallery.Core/Infrastructure/AzureEntityList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@ public class AzureEntityList<T> : IEnumerable<T> where T : ITableEntity, new()
private const string IndexPartitionKey = "INDEX";
private const string IndexRowKey = "0";

private CloudTable _tableRef;
private readonly string _tableName;
private readonly bool _readAccessGeoRedundant;
private readonly Func<string> _connectionStringFactory;

public AzureEntityList(string connStr, string tableName, bool readAccessGeoRedundant)
public AzureEntityList(Func<string> connectionStringFactory, string tableName, bool readAccessGeoRedundant)
{
var tableClient = CloudStorageAccount.Parse(connStr).CreateCloudTableClient();
if (readAccessGeoRedundant)
{
tableClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
}
_tableRef = tableClient.GetTableReference(tableName);
_tableName = tableName ?? throw new ArgumentNullException(nameof(tableName));
_readAccessGeoRedundant = readAccessGeoRedundant;
_connectionStringFactory = connectionStringFactory ?? throw new ArgumentNullException(nameof(connectionStringFactory));

var tableRef = GetTableReference();
// Create the actual Azure Table, if it doesn't yet exist.
bool newTable = _tableRef.CreateIfNotExists();
bool newTable = tableRef.CreateIfNotExists();

// Create the Index if it doesn't yet exist.
bool needsIndex = newTable;
if (!newTable)
{
var indexResult = _tableRef.Execute(
var indexResult = tableRef.Execute(
TableOperation.Retrieve<Index>(IndexPartitionKey, IndexRowKey));

needsIndex = (indexResult.HttpStatusCode == 404);
Expand All @@ -49,7 +49,7 @@ public AzureEntityList(string connStr, string tableName, bool readAccessGeoRedun
if (needsIndex)
{
// Create the index
var result = _tableRef.Execute(
var result = tableRef.Execute(
TableOperation.Insert(new Index
{
Count = 0,
Expand Down Expand Up @@ -102,7 +102,8 @@ public long LongCount
string partitionKey = FormatPartitionKey(page);
string rowKey = FormatRowKey(row);

var response = _tableRef.Execute(TableOperation.Retrieve<T>(partitionKey, rowKey));
var tableRef = GetTableReference();
var response = tableRef.Execute(TableOperation.Retrieve<T>(partitionKey, rowKey));
if (response.HttpStatusCode == 404)
{
throw new ArgumentOutOfRangeException(nameof(index), index, CoreStrings.Http404NotFound);
Expand All @@ -129,8 +130,10 @@ public long LongCount
value.PartitionKey = FormatPartitionKey(page);
value.RowKey = FormatRowKey(row);

var tableRef = GetTableReference();

// Just do an unconditional update - if you wanted any *real* benefit of atomic update then you would need a more complex method signature that calls you back when optimistic updates fail ETAG checks!
_tableRef.Execute(TableOperation.Replace(value));
tableRef.Execute(TableOperation.Replace(value));
}
}

Expand Down Expand Up @@ -161,13 +164,14 @@ public long Add(T entity)
/// </summary>
public IEnumerator<T> GetEnumerator()
{
var tableRef = GetTableReference();
for (long page = 0;; page++)
{
string partitionKey = FormatPartitionKey(page);
var chunkQuery = new TableQuery<T>().Where(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey));

var chunk = _tableRef.ExecuteQuery(chunkQuery).ToArray();
var chunk = tableRef.ExecuteQuery(chunkQuery).ToArray();

foreach (var item in chunk)
{
Expand All @@ -191,6 +195,7 @@ public IEnumerable<T> GetRange(long pos, int n)
int done = 0;
long page = pos / 1000;
long offset = pos % 1000;
var tableRef = GetTableReference();
while (done < n)
{
string partitionKey = FormatPartitionKey(page);
Expand All @@ -201,7 +206,7 @@ public IEnumerable<T> GetRange(long pos, int n)
TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, rowKey)));

var chunk = _tableRef.ExecuteQuery(chunkQuery).ToArray();
var chunk = tableRef.ExecuteQuery(chunkQuery).ToArray();
if (chunk.Length == 0)
{
break; // Reached the end of the list
Expand Down Expand Up @@ -235,9 +240,10 @@ private long AtomicIncrementCount()
// 2) use ETAG to do a conditional +1 update
// 3) retry if that optimistic concurrency attempt failed
long pos = -1; // To avoid compiler warnings, grr - should never be returned
var tableRef = GetTableReference();
DoReplaceWithRetry(() =>
{
var result1 = _tableRef.Execute(
var result1 = tableRef.Execute(
TableOperation.Retrieve<Index>(IndexPartitionKey, IndexRowKey));
ThrowIfErrorStatus(result1);
Expand All @@ -260,6 +266,7 @@ private long AtomicIncrementCount()
private void InsertIfNotExistsWithRetry<T2>(Func<T2> valueGenerator) where T2 : ITableEntity
{
TableResult storeResult;
var tableRef = GetTableReference();
do
{
var entity = valueGenerator();
Expand All @@ -268,7 +275,7 @@ private long AtomicIncrementCount()
// - the dummy MERGES with existing data instead of overwriting it, so no data loss.
// 2) Use its ETAG to conditionally replace the item
// 3) return true if success, false to allow retry on failure
var dummyResult = _tableRef.Execute(
var dummyResult = tableRef.Execute(
TableOperation.InsertOrMerge(new HazardEntry
{
PartitionKey = entity.PartitionKey,
Expand All @@ -281,7 +288,7 @@ private long AtomicIncrementCount()
}

entity.ETag = dummyResult.Etag;
storeResult = _tableRef.Execute(TableOperation.Replace(entity));
storeResult = tableRef.Execute(TableOperation.Replace(entity));
}
while (storeResult.HttpStatusCode == 412);
ThrowIfErrorStatus(storeResult);
Expand All @@ -290,17 +297,19 @@ private long AtomicIncrementCount()
private void DoReplaceWithRetry<T2>(Func<T2> valueGenerator) where T2 : ITableEntity
{
TableResult storeResult;
var tableRef = GetTableReference();
do
{
storeResult = _tableRef.Execute(TableOperation.Replace(valueGenerator.Invoke()));
storeResult = tableRef.Execute(TableOperation.Replace(valueGenerator.Invoke()));
}
while (storeResult.HttpStatusCode == 412);
ThrowIfErrorStatus(storeResult);
}

private Index ReadIndex()
{
var response = _tableRef.Execute(TableOperation.Retrieve<Index>(IndexPartitionKey, IndexRowKey));
var tableRef = GetTableReference();
var response = tableRef.Execute(TableOperation.Retrieve<Index>(IndexPartitionKey, IndexRowKey));
return (Index)response.Result;
}

Expand Down Expand Up @@ -333,6 +342,16 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
return GetEnumerator();
}

private CloudTable GetTableReference()
{
var tableClient = CloudStorageAccount.Parse(_connectionStringFactory()).CreateCloudTableClient();
if (_readAccessGeoRedundant)
{
tableClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
}
return tableClient.GetTableReference(_tableName);
}

class HazardEntry : ITableEntity
{
private const string PlaceHolderPropertyName = "Place_Held";
Expand Down
6 changes: 2 additions & 4 deletions src/NuGetGallery.Core/Infrastructure/TableErrorLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,11 @@ public class TableErrorLog : ErrorLog
{
public const string TableName = "ElmahErrors";

private readonly string _connectionString;
private readonly AzureEntityList<ErrorEntity> _entityList;

public TableErrorLog(string connectionString, bool readAccessGeoRedundant)
public TableErrorLog(Func<string> connectionStringFactory, bool readAccessGeoRedundant)
{
_connectionString = connectionString;
_entityList = new AzureEntityList<ErrorEntity>(connectionString, TableName, readAccessGeoRedundant);
_entityList = new AzureEntityList<ErrorEntity>(connectionStringFactory, TableName, readAccessGeoRedundant);
}

public override ErrorLogEntry GetError(string id)
Expand Down
8 changes: 4 additions & 4 deletions src/NuGetGallery.Core/NuGetGallery.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<Version>5.9.0</Version>
</PackageReference>
<PackageReference Include="NuGet.Services.FeatureFlags">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
<PackageReference Include="WindowsAzure.Storage">
<Version>9.3.3</Version>
Expand All @@ -56,13 +56,13 @@

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<PackageReference Include="NuGet.Services.Messaging.Email">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
<PackageReference Include="NuGet.Services.Validation">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
<PackageReference Include="NuGet.Services.Validation.Issues">
<Version>2.84.0</Version>
<Version>2.86.0</Version>
</PackageReference>
<PackageReference Include="NuGet.StrongName.elmah.corelibrary">
<Version>1.2.2</Version>
Expand Down

0 comments on commit c71e124

Please sign in to comment.