From 7afeaa5e2bba78072a3402ea4be25d519d0e0272 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 01:10:34 +0530 Subject: [PATCH 01/29] first draft --- .../src/Telemetry/ClientTelemetry.cs | 12 ++- .../src/Telemetry/ClientTelemetryHelper.cs | 5 +- .../Telemetry/ClientTelemetryProperties.cs | 3 + .../src/Telemetry/Compute.cs | 11 ++- .../ClientTelemetryTests.cs | 99 +++++++++++++++---- .../ClientTelemetryTests.cs | 1 + 6 files changed, 107 insertions(+), 24 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index cbfb8d9f2d..77787deb54 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -30,9 +30,9 @@ internal class ClientTelemetry : IDisposable { private static readonly Uri endpointUrl = ClientTelemetryOptions.GetClientTelemetryEndpoint(); private static readonly TimeSpan observingWindow = ClientTelemetryOptions.GetScheduledTimeSpan(); + private static readonly string UniqueId = Guid.NewGuid().ToString(); private readonly ClientTelemetryProperties clientTelemetryInfo; - private readonly DocumentClient documentClient; private readonly CosmosHttpClient httpClient; private readonly AuthorizationTokenProvider tokenProvider; @@ -136,14 +136,19 @@ private async Task EnrichAndSendAsync() } // Load host information if not available (it caches the information) - AzureVMMetadata azMetadata = await ClientTelemetryHelper.LoadAzureVmMetaDataAsync(this.httpClient); + AzureVMMetadata azMetadata = await ClientTelemetryHelper.LoadAzureVmMetaDataAsync(this.httpClient, this.cancellationTokenSource); Compute vmInformation = azMetadata?.Compute; if (vmInformation != null) { this.clientTelemetryInfo.ApplicationRegion = vmInformation.Location; this.clientTelemetryInfo.HostEnvInfo = ClientTelemetryOptions.GetHostInformation(vmInformation); + this.clientTelemetryInfo.MachineId = vmInformation.VMId; //TODO: Set AcceleratingNetwork flag from instance metadata once it is available. + } + else + { + this.clientTelemetryInfo.MachineId = ClientTelemetry.UniqueId; } await Task.Delay(observingWindow, this.cancellationTokenSource.Token); @@ -369,7 +374,8 @@ public void Dispose() { this.cancellationTokenSource.Cancel(); this.cancellationTokenSource.Dispose(); - + + this.telemetryTask.Dispose(); this.telemetryTask = null; } } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index 7b4168ece1..6d4cac4728 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -48,7 +48,7 @@ internal static async Task SetAccountNameAsync(DocumentClient /// Collects only application region and environment information /// /// Async Task - internal static async Task LoadAzureVmMetaDataAsync(CosmosHttpClient httpClient) + internal static async Task LoadAzureVmMetaDataAsync(CosmosHttpClient httpClient, CancellationTokenSource cancellationTokenSource) { if (azMetadata == null) { @@ -72,10 +72,9 @@ static ValueTask CreateRequestMessage() resourceType: ResourceType.Telemetry, timeoutPolicy: HttpTimeoutPolicyDefault.Instance, clientSideRequestStatistics: null, - cancellationToken: new CancellationToken()); // Do not want to cancel the whole process if this call fails + cancellationToken: cancellationTokenSource.Token); // Cancel this call if cancel is requested azMetadata = await ClientTelemetryOptions.ProcessResponseAsync(httpResponseMessage); - } catch (Exception ex) { diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs index 215844a65c..a9b2501678 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs @@ -19,6 +19,9 @@ internal sealed class ClientTelemetryProperties [JsonProperty(PropertyName = "clientId")] internal string ClientId { get; } + [JsonProperty(PropertyName = "machineId")] + internal string MachineId { get; set; } + [JsonProperty(PropertyName = "processId")] internal string ProcessId { get; } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs index ea5a29f0a5..bf1e21378e 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs @@ -10,13 +10,14 @@ namespace Microsoft.Azure.Cosmos.Telemetry [Serializable] internal sealed class Compute { - public Compute(string location, string sKU, string azEnvironment, string oSType, string vMSize) + public Compute(string location, string sKU, string azEnvironment, string oSType, string vMSize, string vMId) { this.Location = location; this.SKU = sKU; this.AzEnvironment = azEnvironment; this.OSType = oSType; this.VMSize = vMSize; + this.VMId = vMId; } [JsonProperty(PropertyName = "location")] @@ -33,6 +34,14 @@ public Compute(string location, string sKU, string azEnvironment, string oSType, [JsonProperty(PropertyName = "vmSize")] internal string VMSize { get; } + + [JsonProperty(PropertyName = "vmId")] + internal string VMId { get; } + + public override string ToString() + { + return this.VMId; + } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index f5b063e411..f6830fcd34 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -22,6 +22,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using Newtonsoft.Json; using Documents.Rntbd; using System.Globalization; + using System.Linq; [TestClass] public class ClientTelemetryTests : BaseCosmosClientHelper @@ -38,6 +39,9 @@ public class ClientTelemetryTests : BaseCosmosClientHelper private IDictionary expectedMetricNameUnitMap; + private HttpClientHandlerHelper httpHandler; + private HttpClientHandlerHelper httpHandlerForNonAzureInstance; + [ClassInitialize] public static void ClassInitialize(TestContext context) { @@ -57,7 +61,7 @@ public void TestInitialize() { this.actualInfo = new List(); - HttpClientHandlerHelper httpHandler = new HttpClientHandlerHelper + this.httpHandler = new HttpClientHandlerHelper { RequestCallBack = (request, cancellation) => { @@ -87,6 +91,27 @@ public void TestInitialize() } }; + this.httpHandlerForNonAzureInstance = new HttpClientHandlerHelper + { + RequestCallBack = (request, cancellation) => + { + if (request.RequestUri.AbsoluteUri.Equals(ClientTelemetryOptions.GetClientTelemetryEndpoint().AbsoluteUri)) + { + HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); + + string jsonObject = request.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + lock (this.actualInfo) + { + this.actualInfo.Add(JsonConvert.DeserializeObject(jsonObject)); + } + + return Task.FromResult(result); + } + return null; + } + }; + this.preferredRegionList = new List { "region1", @@ -103,8 +128,7 @@ public void TestInitialize() }; this.cosmosClientBuilder = TestCommon.GetDefaultConfiguration() - .WithApplicationPreferredRegions(this.preferredRegionList) - .WithHttpClientFactory(() => new HttpClient(httpHandler)); + .WithApplicationPreferredRegions(this.preferredRegionList); } [ClassCleanup] @@ -152,11 +176,15 @@ public async Task Cleanup() } [TestMethod] - [DataRow(ConnectionMode.Direct)] - [DataRow(ConnectionMode.Gateway)] - public async Task PointSuccessOperationsTest(ConnectionMode mode) + [DataRow(ConnectionMode.Direct, true)] + [DataRow(ConnectionMode.Gateway, true)] + [DataRow(ConnectionMode.Direct, false)] + [DataRow(ConnectionMode.Gateway, false)] + public async Task PointSuccessOperationsTest(ConnectionMode mode, bool isAzureInstance) { - Container container = await this.CreateClientAndContainer(mode); + Container container = await this.CreateClientAndContainer( + mode: mode, + isAzureInstance: isAzureInstance); // Create an item ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity("MyTestPkValue"); @@ -196,7 +224,8 @@ public async Task PointSuccessOperationsTest(ConnectionMode mode) }; await this.WaitAndAssert(expectedOperationCount: 12, - expectedOperationRecordCountMap: expectedRecordCountInOperation); + expectedOperationRecordCountMap: expectedRecordCountInOperation, + isAzureInstance: isAzureInstance); } [TestMethod] @@ -723,7 +752,8 @@ private async Task WaitAndAssert( int expectedOperationCount = 0, Microsoft.Azure.Cosmos.ConsistencyLevel? expectedConsistencyLevel = null, IDictionary expectedOperationRecordCountMap = null, - string expectedSubstatuscode = null) + string expectedSubstatuscode = null, + bool isAzureInstance = false) { Assert.IsNotNull(this.actualInfo, "Telemetry Information not available"); @@ -732,7 +762,7 @@ private async Task WaitAndAssert( Stopwatch stopwatch = Stopwatch.StartNew(); do { - await Task.Delay(TimeSpan.FromMilliseconds(1500)); // wait at least for 1 round of telemetry + await Task.Delay(TimeSpan.FromMilliseconds(2000)); // wait at least for 1 round of telemetry HashSet actualOperationSet = new HashSet(); lock (this.actualInfo) @@ -766,9 +796,19 @@ private async Task WaitAndAssert( this.expectedMetricNameUnitMap.Add(ClientTelemetryOptions.NumberOfTcpConnectionName, ClientTelemetryOptions.NumberOfTcpConnectionUnit); } - ClientTelemetryTests.AssertAccountLevelInformation(localCopyOfActualInfo, actualOperationList, actualSystemInformation); - ClientTelemetryTests.AssertOperationLevelInformation(expectedConsistencyLevel, expectedOperationRecordCountMap, actualOperationList, expectedSubstatuscode); - ClientTelemetryTests.AssertSystemLevelInformation(actualSystemInformation, this.expectedMetricNameUnitMap); + ClientTelemetryTests.AssertAccountLevelInformation( + localCopyOfActualInfo: localCopyOfActualInfo, + actualOperationList: actualOperationList, + actualSystemInformation: actualSystemInformation, + isAzureInstance: isAzureInstance); + + ClientTelemetryTests.AssertOperationLevelInformation( + expectedConsistencyLevel: expectedConsistencyLevel, + expectedOperationRecordCountMap: expectedOperationRecordCountMap, + actualOperationList: actualOperationList, + expectedSubstatuscode: expectedSubstatuscode); + + ClientTelemetryTests.AssertSystemLevelInformation(actualSystemInformation); } private static void AssertSystemLevelInformation(List actualSystemInformation, IDictionary expectedMetricNameUnitMap) @@ -851,8 +891,14 @@ private static void AssertOperationLevelInformation( } } - private static void AssertAccountLevelInformation(List localCopyOfActualInfo, List actualOperationList, List actualSystemInformation) + private static void AssertAccountLevelInformation( + List localCopyOfActualInfo, + List actualOperationList, + List actualSystemInformation, + bool isAzureInstance) { + ISet machineId = new HashSet(); + // Asserting If basic client telemetry object is as expected foreach (ClientTelemetryProperties telemetryInfo in localCopyOfActualInfo) { @@ -867,7 +913,7 @@ private static void AssertAccountLevelInformation(List CreateClientAndContainer(ConnectionMode mode, Microsoft.Azure.Cosmos.ConsistencyLevel? consistency = null, - bool isLargeContainer = false) + bool isLargeContainer = false, + bool isAzureInstance = false) { if (consistency.HasValue) { - this.cosmosClientBuilder = this.cosmosClientBuilder.WithConsistencyLevel(consistency.Value); + this.cosmosClientBuilder = this.cosmosClientBuilder + .WithConsistencyLevel(consistency.Value); } + this.cosmosClientBuilder = this.cosmosClientBuilder + .WithHttpClientFactory(() => + isAzureInstance ? new HttpClient(this.httpHandler) : new HttpClient(this.httpHandlerForNonAzureInstance)); + this.cosmosClient = mode == ConnectionMode.Gateway ? this.cosmosClientBuilder.WithConnectionModeGateway().Build() : this.cosmosClientBuilder.Build(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs index 1e9d215dfb..19513738e0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs @@ -45,6 +45,7 @@ public async Task ParseAzureVMMetadataTest() Assert.AreEqual("AzurePublicCloud", metadata.Compute.AzEnvironment); Assert.AreEqual("Linux", metadata.Compute.OSType); Assert.AreEqual("Standard_D2s_v3", metadata.Compute.VMSize); + Assert.AreEqual("d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", metadata.Compute.VMId); } [TestMethod] From e89db269ef76ce270ad72209bf79c47d662660be Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 17:27:37 +0530 Subject: [PATCH 02/29] bug fix and code refcator --- .../src/Telemetry/AzureVMMetadata.cs | 2 +- .../src/Telemetry/ClientTelemetry.cs | 7 +------ .../src/Telemetry/ClientTelemetryHelper.cs | 14 ++++++++++++++ Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs | 6 +++++- .../ClientTelemetryTests.cs | 10 ++++++++-- .../Utils/HttpHandlerHelper.cs | 1 - 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs b/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs index b1547b546d..c5fbcced25 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs @@ -16,6 +16,6 @@ public AzureVMMetadata(Compute compute) } [JsonProperty(PropertyName = "compute")] - internal Compute Compute { get; } + internal Compute Compute { get; set; } } } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index 77787deb54..9fe735faba 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -30,7 +30,7 @@ internal class ClientTelemetry : IDisposable { private static readonly Uri endpointUrl = ClientTelemetryOptions.GetClientTelemetryEndpoint(); private static readonly TimeSpan observingWindow = ClientTelemetryOptions.GetScheduledTimeSpan(); - private static readonly string UniqueId = Guid.NewGuid().ToString(); + internal static readonly string UniqueId = "vmId:" + Guid.NewGuid().ToString(); private readonly ClientTelemetryProperties clientTelemetryInfo; private readonly DocumentClient documentClient; @@ -145,10 +145,6 @@ private async Task EnrichAndSendAsync() this.clientTelemetryInfo.HostEnvInfo = ClientTelemetryOptions.GetHostInformation(vmInformation); this.clientTelemetryInfo.MachineId = vmInformation.VMId; //TODO: Set AcceleratingNetwork flag from instance metadata once it is available. - } - else - { - this.clientTelemetryInfo.MachineId = ClientTelemetry.UniqueId; } await Task.Delay(observingWindow, this.cancellationTokenSource.Token); @@ -375,7 +371,6 @@ public void Dispose() this.cancellationTokenSource.Cancel(); this.cancellationTokenSource.Dispose(); - this.telemetryTask.Dispose(); this.telemetryTask = null; } } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index 6d4cac4728..31a7f36265 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -80,6 +80,20 @@ static ValueTask CreateRequestMessage() { DefaultTrace.TraceError("Exception in LoadAzureVmMetaDataAsync() {0}", ex.Message); } + finally + { + // If above call failed for any reason + if (azMetadata == null) + { + azMetadata = new AzureVMMetadata(new Compute()); + } + + if (string.IsNullOrEmpty(azMetadata.Compute.VMId)) + { + // Assign a random unique Id + azMetadata.Compute.VMId = ClientTelemetry.UniqueId; + } + } } return azMetadata; diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs index bf1e21378e..7c789c24ba 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs @@ -10,6 +10,10 @@ namespace Microsoft.Azure.Cosmos.Telemetry [Serializable] internal sealed class Compute { + public Compute() + { + } + public Compute(string location, string sKU, string azEnvironment, string oSType, string vMSize, string vMId) { this.Location = location; @@ -36,7 +40,7 @@ public Compute(string location, string sKU, string azEnvironment, string oSType, internal string VMSize { get; } [JsonProperty(PropertyName = "vmId")] - internal string VMId { get; } + internal string VMId { get; set; } public override string ToString() { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index f6830fcd34..4211e49954 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -182,6 +182,9 @@ public async Task Cleanup() [DataRow(ConnectionMode.Gateway, false)] public async Task PointSuccessOperationsTest(ConnectionMode mode, bool isAzureInstance) { + // Clean cached information + ClientTelemetryHelper.azMetadata = null; + Container container = await this.CreateClientAndContainer( mode: mode, isAzureInstance: isAzureInstance); @@ -926,11 +929,14 @@ private static void AssertAccountLevelInformation( Assert.IsNotNull(telemetryInfo.UserAgent); Assert.IsNotNull(telemetryInfo.ConnectionMode); - machineId.Add(telemetryInfo.MachineId); + if(!string.IsNullOrEmpty(telemetryInfo.MachineId)) + { + machineId.Add(telemetryInfo.MachineId); + } } Assert.AreEqual(1, machineId.Count); - Console.WriteLine(machineId.ToList()[0]); + if(isAzureInstance) { Assert.AreEqual("d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/HttpHandlerHelper.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/HttpHandlerHelper.cs index ac92a882e8..990b17560d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/HttpHandlerHelper.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/HttpHandlerHelper.cs @@ -22,7 +22,6 @@ protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { - Console.WriteLine(request.RequestUri.ToString()); return this.MockHttpHandler.SendAsync(request, cancellationToken); } } From 65b89e5c88bb8b44ff7fc990d3f0188b0f2dd21c Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 17:29:35 +0530 Subject: [PATCH 03/29] code clean --- Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs b/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs index c5fbcced25..b1547b546d 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/AzureVMMetadata.cs @@ -16,6 +16,6 @@ public AzureVMMetadata(Compute compute) } [JsonProperty(PropertyName = "compute")] - internal Compute Compute { get; set; } + internal Compute Compute { get; } } } From 74872bc4ed20116e7c14b24bb143446bd4ddc422 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 22:50:04 +0530 Subject: [PATCH 04/29] client telemetry with machine id --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 4 +++ .../src/Telemetry/ClientTelemetry.cs | 12 +++++---- .../src/Telemetry/ClientTelemetryHelper.cs | 14 ----------- .../src/Telemetry/ClientTelemetryOptions.cs | 1 + .../src/Telemetry/Compute.cs | 22 ++++++++-------- .../ClientTelemetryTests.cs | 25 +++++++++++-------- .../ClientTelemetryTests.cs | 2 +- 7 files changed, 38 insertions(+), 42 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index abd4e40b87..14b84f49ad 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -22,6 +22,7 @@ namespace Microsoft.Azure.Cosmos using Microsoft.Azure.Cosmos.Query; using Microsoft.Azure.Cosmos.Query.Core.QueryPlan; using Microsoft.Azure.Cosmos.Routing; + using Microsoft.Azure.Cosmos.Telemetry; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Cosmos.Tracing.TraceData; using Microsoft.Azure.Documents; @@ -958,6 +959,9 @@ internal virtual void Initialize(Uri serviceEndpoint, // Always called from under the lock except when called from Intilialize method during construction. private async Task GetInitializationTaskAsync(IStoreClientFactory storeClientFactory) { + // Loading VM Information (non blocking call and initialization won't fail if this call fails) + await ClientTelemetryHelper.LoadAzureVmMetaDataAsync(this.httpClient, new CancellationTokenSource()); + await this.InitializeGatewayConfigurationReaderAsync(); if (this.desiredConsistencyLevel.HasValue) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index 9fe735faba..e8862bd733 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -30,7 +30,7 @@ internal class ClientTelemetry : IDisposable { private static readonly Uri endpointUrl = ClientTelemetryOptions.GetClientTelemetryEndpoint(); private static readonly TimeSpan observingWindow = ClientTelemetryOptions.GetScheduledTimeSpan(); - internal static readonly string UniqueId = "vmId:" + Guid.NewGuid().ToString(); + internal static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); private readonly ClientTelemetryProperties clientTelemetryInfo; private readonly DocumentClient documentClient; @@ -135,16 +135,18 @@ private async Task EnrichAndSendAsync() this.clientTelemetryInfo.GlobalDatabaseAccountName = accountProperties?.Id; } - // Load host information if not available (it caches the information) - AzureVMMetadata azMetadata = await ClientTelemetryHelper.LoadAzureVmMetaDataAsync(this.httpClient, this.cancellationTokenSource); - - Compute vmInformation = azMetadata?.Compute; + // Load host information from cache + Compute vmInformation = ClientTelemetryHelper.azMetadata?.Compute; if (vmInformation != null) { this.clientTelemetryInfo.ApplicationRegion = vmInformation.Location; this.clientTelemetryInfo.HostEnvInfo = ClientTelemetryOptions.GetHostInformation(vmInformation); this.clientTelemetryInfo.MachineId = vmInformation.VMId; //TODO: Set AcceleratingNetwork flag from instance metadata once it is available. + } + else + { + this.clientTelemetryInfo.MachineId = ClientTelemetry.UniqueId; } await Task.Delay(observingWindow, this.cancellationTokenSource.Token); diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index 31a7f36265..6d4cac4728 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -80,20 +80,6 @@ static ValueTask CreateRequestMessage() { DefaultTrace.TraceError("Exception in LoadAzureVmMetaDataAsync() {0}", ex.Message); } - finally - { - // If above call failed for any reason - if (azMetadata == null) - { - azMetadata = new AzureVMMetadata(new Compute()); - } - - if (string.IsNullOrEmpty(azMetadata.Compute.VMId)) - { - // Assign a random unique Id - azMetadata.Compute.VMId = ClientTelemetry.UniqueId; - } - } } return azMetadata; diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs index e7f87790bb..9a6c06f6a3 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs @@ -161,6 +161,7 @@ internal static async Task ProcessResponseAsync(HttpResponseMes return null; } string jsonVmInfo = await httpResponseMessage.Content.ReadAsStringAsync(); + return JObject.Parse(jsonVmInfo).ToObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs index 7c789c24ba..03d2cdb40f 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/Compute.cs @@ -10,18 +10,21 @@ namespace Microsoft.Azure.Cosmos.Telemetry [Serializable] internal sealed class Compute { - public Compute() - { - } - - public Compute(string location, string sKU, string azEnvironment, string oSType, string vMSize, string vMId) + [JsonConstructor] + public Compute( + string vMId, + string location, + string sKU, + string azEnvironment, + string oSType, + string vMSize) { this.Location = location; this.SKU = sKU; this.AzEnvironment = azEnvironment; this.OSType = oSType; this.VMSize = vMSize; - this.VMId = vMId; + this.VMId = "vmId:" + vMId; } [JsonProperty(PropertyName = "location")] @@ -40,12 +43,7 @@ public Compute(string location, string sKU, string azEnvironment, string oSType, internal string VMSize { get; } [JsonProperty(PropertyName = "vmId")] - internal string VMId { get; set; } - - public override string ToString() - { - return this.VMId; - } + internal string VMId { get; } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 4211e49954..077670a680 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -756,7 +756,7 @@ private async Task WaitAndAssert( Microsoft.Azure.Cosmos.ConsistencyLevel? expectedConsistencyLevel = null, IDictionary expectedOperationRecordCountMap = null, string expectedSubstatuscode = null, - bool isAzureInstance = false) + bool? isAzureInstance = null) { Assert.IsNotNull(this.actualInfo, "Telemetry Information not available"); @@ -895,10 +895,10 @@ private static void AssertOperationLevelInformation( } private static void AssertAccountLevelInformation( - List localCopyOfActualInfo, - List actualOperationList, + List localCopyOfActualInfo, + List actualOperationList, List actualSystemInformation, - bool isAzureInstance) + bool? isAzureInstance) { ISet machineId = new HashSet(); @@ -937,14 +937,19 @@ private static void AssertAccountLevelInformation( Assert.AreEqual(1, machineId.Count); - if(isAzureInstance) + if(isAzureInstance.HasValue) { - Assert.AreEqual("d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); - } - else - { - Assert.AreNotEqual("d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); + if (isAzureInstance.Value) + { + Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); + } + else + { + Assert.AreNotEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); + Assert.IsTrue(machineId.ToList()[0].Contains("uuid:"), machineId.ToList()[0]); + } } + } private static ItemBatchOperation CreateItem(string itemId) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs index 19513738e0..ea2aa694d0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs @@ -45,7 +45,7 @@ public async Task ParseAzureVMMetadataTest() Assert.AreEqual("AzurePublicCloud", metadata.Compute.AzEnvironment); Assert.AreEqual("Linux", metadata.Compute.OSType); Assert.AreEqual("Standard_D2s_v3", metadata.Compute.VMSize); - Assert.AreEqual("d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", metadata.Compute.VMId); + Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", metadata.Compute.VMId); } [TestMethod] From 439a9f264797eaeef250dc95b06a5dd27327c7ce Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 23:36:54 +0530 Subject: [PATCH 05/29] add machineid to diagnostics --- Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs | 8 +++----- .../src/Telemetry/ClientTelemetryHelper.cs | 3 ++- .../Tracing/TraceData/ClientConfigurationTraceDatum.cs | 4 +++- .../src/Tracing/TraceWriter.TraceTextWriter.cs | 2 ++ .../ClientTelemetryTests.cs | 2 ++ 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index e8862bd733..e0bc32c9ee 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -141,14 +141,12 @@ private async Task EnrichAndSendAsync() { this.clientTelemetryInfo.ApplicationRegion = vmInformation.Location; this.clientTelemetryInfo.HostEnvInfo = ClientTelemetryOptions.GetHostInformation(vmInformation); - this.clientTelemetryInfo.MachineId = vmInformation.VMId; + //TODO: Set AcceleratingNetwork flag from instance metadata once it is available. - } - else - { - this.clientTelemetryInfo.MachineId = ClientTelemetry.UniqueId; } + this.clientTelemetryInfo.MachineId = ClientTelemetryHelper.GetMachineId(); + await Task.Delay(observingWindow, this.cancellationTokenSource.Token); // If cancellation is requested after the delay then return from here. diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index 6d4cac4728..c220bf4acf 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -117,7 +117,7 @@ internal static void RecordSystemUsage( { systemInfoCollection.Add(TelemetrySystemUsage.GetTcpConnectionCount(systemUsageHistory.Values)); } - + } /// @@ -185,5 +185,6 @@ internal static string GetContactedRegions(CosmosDiagnostics cosmosDiagnostics) return regionsContacted.ToString(); } + } } diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs index 7fa91b5fd5..7aa3f9dd38 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos.Tracing.TraceData using System; using System.Globalization; using Microsoft.Azure.Cosmos.Json; + using Microsoft.Azure.Cosmos.Telemetry; internal sealed class ClientConfigurationTraceDatum : TraceDatum { @@ -81,7 +82,8 @@ private ReadOnlyMemory GetSerializedDatum() jsonTextWriter.WriteFieldName("Client Created Time Utc"); jsonTextWriter.WriteStringValue(this.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)); - + jsonTextWriter.WriteFieldName("MachineId"); + jsonTextWriter.WriteStringValue(ClientTelemetryHelper.GetMachineId()); jsonTextWriter.WriteFieldName("NumberOfClientsCreated"); jsonTextWriter.WriteNumber64Value(this.cachedNumberOfClientCreated); jsonTextWriter.WriteFieldName("NumberOfActiveClients"); diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs index 8fc6b214c7..e32999d04e 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs @@ -11,6 +11,7 @@ namespace Microsoft.Azure.Cosmos.Tracing using System.Linq; using System.Text; using Microsoft.Azure.Cosmos.Query.Core.Metrics; + using Microsoft.Azure.Cosmos.Telemetry; using Microsoft.Azure.Cosmos.Tracing.TraceData; using static Microsoft.Azure.Cosmos.Tracing.TraceData.ClientSideRequestStatisticsTraceDatum; @@ -478,6 +479,7 @@ public void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Client Configuration"); stringBuilder.AppendLine($"Client Created Time: {clientConfigurationTraceDatum.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)}"); + stringBuilder.AppendLine($"Machine Id: {ClientTelemetryHelper.GetMachineId()}"); stringBuilder.AppendLine($"Number Of Clients Created: {CosmosClient.numberOfClientsCreated}"); stringBuilder.AppendLine($"Number Of Active Clients: {CosmosClient.NumberOfActiveClients}"); stringBuilder.AppendLine($"User Agent: {clientConfigurationTraceDatum.UserAgentContainer.UserAgent}"); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 077670a680..c468fb858e 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -194,6 +194,8 @@ public async Task PointSuccessOperationsTest(ConnectionMode mode, bool isAzureIn ItemResponse createResponse = await container.CreateItemAsync(testItem); ToDoActivity testItemCreated = createResponse.Resource; + Console.WriteLine(createResponse.Diagnostics.ToString()); + // Read an Item await container.ReadItemAsync(testItem.id, new Cosmos.PartitionKey(testItem.id)); From abb504764b5d23a5504dd3f2f718d48f23c3dc90 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Tue, 22 Mar 2022 23:42:41 +0530 Subject: [PATCH 06/29] code refactor --- .../src/Telemetry/ClientTelemetryOptions.cs | 1 - .../src/Telemetry/ClientTelemetryProperties.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs index 9a6c06f6a3..e7f87790bb 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs @@ -161,7 +161,6 @@ internal static async Task ProcessResponseAsync(HttpResponseMes return null; } string jsonVmInfo = await httpResponseMessage.Content.ReadAsStringAsync(); - return JObject.Parse(jsonVmInfo).ToObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs index a9b2501678..1cab0ff889 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryProperties.cs @@ -100,7 +100,8 @@ public ClientTelemetryProperties(string dateTimeUtc, IReadOnlyList preferredRegions, List systemInfo, List cacheRefreshInfo, - List operationInfo) + List operationInfo, + string machineId) { this.DateTimeUtc = dateTimeUtc; this.ClientId = clientId; @@ -115,6 +116,7 @@ public ClientTelemetryProperties(string dateTimeUtc, this.CacheRefreshInfo = cacheRefreshInfo; this.OperationInfo = operationInfo; this.PreferredRegions = preferredRegions; + this.MachineId = machineId; } } } From e8c3bbb78afb5a884785901040f3ad314108b33f Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 23 Mar 2022 21:49:56 +0530 Subject: [PATCH 07/29] remove console statmenet --- .../ClientTelemetryTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index c468fb858e..077670a680 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -194,8 +194,6 @@ public async Task PointSuccessOperationsTest(ConnectionMode mode, bool isAzureIn ItemResponse createResponse = await container.CreateItemAsync(testItem); ToDoActivity testItemCreated = createResponse.Resource; - Console.WriteLine(createResponse.Diagnostics.ToString()); - // Read an Item await container.ReadItemAsync(testItem.id, new Cosmos.PartitionKey(testItem.id)); From 037f72990e19000bd6bf898b52ba9d6f775c766e Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 23 Mar 2022 22:35:15 +0530 Subject: [PATCH 08/29] fix test --- .../ClientTelemetryTests.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 077670a680..ecef86bdc8 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -721,7 +721,9 @@ public async Task CreateItemWithSubStatusCodeTest(ConnectionMode mode) this.cosmosClientBuilder = this.cosmosClientBuilder .WithHttpClientFactory(() => new HttpClient(httpHandler)); - Container container = await this.CreateClientAndContainer(mode); + Container container = await this.CreateClientAndContainer( + mode: mode, + customHandler: httpHandler); try { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity("MyTestPkValue"); @@ -961,7 +963,8 @@ private static ItemBatchOperation CreateItem(string itemId) private async Task CreateClientAndContainer(ConnectionMode mode, Microsoft.Azure.Cosmos.ConsistencyLevel? consistency = null, bool isLargeContainer = false, - bool isAzureInstance = false) + bool isAzureInstance = false, + HttpClientHandlerHelper customHandler = null) { if (consistency.HasValue) { @@ -969,9 +972,18 @@ private async Task CreateClientAndContainer(ConnectionMode mode, .WithConsistencyLevel(consistency.Value); } + HttpClientHandlerHelper handlerHelper; + if (customHandler == null) + { + handlerHelper = isAzureInstance ? this.httpHandler : this.httpHandlerForNonAzureInstance; + } + else + { + handlerHelper = customHandler; + } + this.cosmosClientBuilder = this.cosmosClientBuilder - .WithHttpClientFactory(() => - isAzureInstance ? new HttpClient(this.httpHandler) : new HttpClient(this.httpHandlerForNonAzureInstance)); + .WithHttpClientFactory(() => new HttpClient(handlerHelper)); this.cosmosClient = mode == ConnectionMode.Gateway ? this.cosmosClientBuilder.WithConnectionModeGateway().Build() From ac73fd9b060b8cd1e3cebccf98b74e5844b025f1 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 24 Mar 2022 17:47:36 +0530 Subject: [PATCH 09/29] dispose cache on dispose --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 3 +++ Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs | 1 - Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs | 1 + .../ClientTelemetryTests.cs | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 14b84f49ad..5bf87f112c 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -1260,6 +1260,9 @@ public void Dispose() this.initTaskCache = null; } + // Clean cached account information + ClientTelemetryHelper.azMetadata = null; + DefaultTrace.TraceInformation("DocumentClient with id {0} disposed.", this.traceId); DefaultTrace.Flush(); diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index e0bc32c9ee..32c04c01df 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -30,7 +30,6 @@ internal class ClientTelemetry : IDisposable { private static readonly Uri endpointUrl = ClientTelemetryOptions.GetClientTelemetryEndpoint(); private static readonly TimeSpan observingWindow = ClientTelemetryOptions.GetScheduledTimeSpan(); - internal static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); private readonly ClientTelemetryProperties clientTelemetryInfo; private readonly DocumentClient documentClient; diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index c220bf4acf..c52e149f17 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -19,6 +19,7 @@ internal static class ClientTelemetryHelper internal static AzureVMMetadata azMetadata = null; private static readonly Uri vmMetadataEndpointUrl = ClientTelemetryOptions.GetVmMetadataUrl(); + private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); /// /// Task to get Account Properties from cache if available otherwise make a network call. diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index ecef86bdc8..551627f191 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -767,7 +767,7 @@ private async Task WaitAndAssert( Stopwatch stopwatch = Stopwatch.StartNew(); do { - await Task.Delay(TimeSpan.FromMilliseconds(2000)); // wait at least for 1 round of telemetry + await Task.Delay(TimeSpan.FromMilliseconds(1500)); // wait at least for 1 round of telemetry HashSet actualOperationSet = new HashSet(); lock (this.actualInfo) From 6ca17f9609a2c9926c41162c8e9eff38fe30ca01 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 26 Mar 2022 03:42:25 +0530 Subject: [PATCH 10/29] code refactor --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 10 +- .../HttpClient/HttpTimeoutPolicyNoRetry.cs | 44 ++++++ .../src/Telemetry/ClientTelemetry.cs | 4 +- .../src/Telemetry/ClientTelemetryHelper.cs | 48 ------- .../src/Telemetry/ClientTelemetryOptions.cs | 31 ---- .../src/Telemetry/VmMetadataApiHandler.cs | 136 ++++++++++++++++++ .../ClientConfigurationTraceDatum.cs | 2 +- .../Tracing/TraceWriter.TraceTextWriter.cs | 2 +- .../ClientTelemetryTests.cs | 9 +- .../ClientTests.cs | 14 +- .../ClientTelemetryTests.cs | 2 +- 11 files changed, 205 insertions(+), 97 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyNoRetry.cs create mode 100644 Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 5bf87f112c..04c63b8746 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -174,6 +174,8 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private event EventHandler receivedResponse; private Func transportClientHandlerFactory; + private VmMetadataApiHandler vmMetadataApiHandler; + /// /// Initializes a new instance of the class using the /// specified Azure Cosmos DB service endpoint, key, and connection policy for the Azure Cosmos DB service. @@ -898,6 +900,9 @@ internal virtual void Initialize(Uri serviceEndpoint, this.sendingRequest, this.receivedResponse); + // Loading VM Information (non blocking call and initialization won't fail if this call fails) + this.vmMetadataApiHandler = VmMetadataApiHandler.Initialize(this.httpClient); + if (sessionContainer != null) { this.sessionContainer = sessionContainer; @@ -959,9 +964,6 @@ internal virtual void Initialize(Uri serviceEndpoint, // Always called from under the lock except when called from Intilialize method during construction. private async Task GetInitializationTaskAsync(IStoreClientFactory storeClientFactory) { - // Loading VM Information (non blocking call and initialization won't fail if this call fails) - await ClientTelemetryHelper.LoadAzureVmMetaDataAsync(this.httpClient, new CancellationTokenSource()); - await this.InitializeGatewayConfigurationReaderAsync(); if (this.desiredConsistencyLevel.HasValue) @@ -1261,7 +1263,7 @@ public void Dispose() } // Clean cached account information - ClientTelemetryHelper.azMetadata = null; + this.vmMetadataApiHandler.Dispose(); DefaultTrace.TraceInformation("DocumentClient with id {0} disposed.", this.traceId); DefaultTrace.Flush(); diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyNoRetry.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyNoRetry.cs new file mode 100644 index 0000000000..75d8dfe904 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyNoRetry.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Collections.Generic; + using System.Net.Http; + using System.Text; + + internal sealed class HttpTimeoutPolicyNoRetry : HttpTimeoutPolicy + { + public static readonly HttpTimeoutPolicy Instance = new HttpTimeoutPolicyNoRetry(); + private static readonly string Name = nameof(HttpTimeoutPolicyNoRetry); + + private HttpTimeoutPolicyNoRetry() + { + } + + private readonly IReadOnlyList<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> TimeoutsAndDelays = new List<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)>(); + + public override string TimeoutPolicyName => HttpTimeoutPolicyNoRetry.Name; + + public override TimeSpan MaximumRetryTimeLimit => TimeSpan.Zero; + + public override int TotalRetryCount => 0; + + public override IEnumerator<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> GetTimeoutEnumerator() + { + return this.TimeoutsAndDelays.GetEnumerator(); + } + + // Always Unsafe to retry + public override bool IsSafeToRetry(HttpMethod httpMethod) + { + return false; + } + + public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, HttpResponseMessage responseMessage) + { + return false; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index 32c04c01df..b5a2a11d72 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -135,7 +135,7 @@ private async Task EnrichAndSendAsync() } // Load host information from cache - Compute vmInformation = ClientTelemetryHelper.azMetadata?.Compute; + Compute vmInformation = VmMetadataApiHandler.GetMachineInfo(); if (vmInformation != null) { this.clientTelemetryInfo.ApplicationRegion = vmInformation.Location; @@ -144,7 +144,7 @@ private async Task EnrichAndSendAsync() //TODO: Set AcceleratingNetwork flag from instance metadata once it is available. } - this.clientTelemetryInfo.MachineId = ClientTelemetryHelper.GetMachineId(); + this.clientTelemetryInfo.MachineId = VmMetadataApiHandler.GetMachineId(); await Task.Delay(observingWindow, this.cancellationTokenSource.Token); diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs index c52e149f17..963dfd0c4e 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryHelper.cs @@ -16,11 +16,6 @@ namespace Microsoft.Azure.Cosmos.Telemetry internal static class ClientTelemetryHelper { - internal static AzureVMMetadata azMetadata = null; - - private static readonly Uri vmMetadataEndpointUrl = ClientTelemetryOptions.GetVmMetadataUrl(); - private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); - /// /// Task to get Account Properties from cache if available otherwise make a network call. /// @@ -43,49 +38,6 @@ internal static async Task SetAccountNameAsync(DocumentClient return null; } - /// - /// Task to collect virtual machine metadata information. using instance metedata service API. - /// ref: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows - /// Collects only application region and environment information - /// - /// Async Task - internal static async Task LoadAzureVmMetaDataAsync(CosmosHttpClient httpClient, CancellationTokenSource cancellationTokenSource) - { - if (azMetadata == null) - { - DefaultTrace.TraceVerbose("Getting VM Metadata Information for Telemetry."); - try - { - static ValueTask CreateRequestMessage() - { - HttpRequestMessage request = new HttpRequestMessage() - { - RequestUri = vmMetadataEndpointUrl, - Method = HttpMethod.Get, - }; - request.Headers.Add("Metadata", "true"); - - return new ValueTask(request); - } - - using HttpResponseMessage httpResponseMessage = await httpClient - .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, - resourceType: ResourceType.Telemetry, - timeoutPolicy: HttpTimeoutPolicyDefault.Instance, - clientSideRequestStatistics: null, - cancellationToken: cancellationTokenSource.Token); // Cancel this call if cancel is requested - - azMetadata = await ClientTelemetryOptions.ProcessResponseAsync(httpResponseMessage); - } - catch (Exception ex) - { - DefaultTrace.TraceError("Exception in LoadAzureVmMetaDataAsync() {0}", ex.Message); - } - } - - return azMetadata; - } - /// /// Record System Usage and update passed system Info collection. Right now, it collects following metrics /// 1) CPU Usage diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs index e7f87790bb..0e4e50f4b0 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetryOptions.cs @@ -4,12 +4,9 @@ namespace Microsoft.Azure.Cosmos.Telemetry { using System; - using System.Net.Http; - using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Core.Trace; using Microsoft.Azure.Documents; using Newtonsoft.Json; - using Newtonsoft.Json.Linq; internal static class ClientTelemetryOptions { @@ -73,7 +70,6 @@ internal static class ClientTelemetryOptions internal const string IsThreadStarvingName = "SystemPool_IsThreadStarving_True"; internal const string IsThreadStarvingUnit = "Count"; - internal const string DefaultVmMetadataUrL = "http://169.254.169.254/metadata/instance?api-version=2020-06-01"; internal const double DefaultTimeStampInSeconds = 600; internal const double Percentile50 = 50.0; internal const double Percentile90 = 90.0; @@ -92,7 +88,6 @@ internal static class ClientTelemetryOptions internal static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; - private static Uri vmMetadataUrl; private static Uri clientTelemetryEndpoint; private static string environmentName; private static TimeSpan scheduledTimeSpan = TimeSpan.Zero; @@ -108,22 +103,6 @@ internal static bool IsClientTelemetryEnabled() return isTelemetryEnabled; } - internal static Uri GetVmMetadataUrl() - { - if (vmMetadataUrl == null) - { - string vmMetadataUrlProp = ConfigurationManager.GetEnvironmentVariable( - EnvPropsClientTelemetryVmMetadataUrl, DefaultVmMetadataUrL); - if (!String.IsNullOrEmpty(vmMetadataUrlProp)) - { - vmMetadataUrl = new Uri(vmMetadataUrlProp); - } - - DefaultTrace.TraceInformation($"VM metadata URL for telemetry {vmMetadataUrlProp}"); - } - return vmMetadataUrl; - } - internal static TimeSpan GetScheduledTimeSpan() { if (scheduledTimeSpan.Equals(TimeSpan.Zero)) @@ -154,16 +133,6 @@ internal static TimeSpan GetScheduledTimeSpan() return scheduledTimeSpan; } - internal static async Task ProcessResponseAsync(HttpResponseMessage httpResponseMessage) - { - if (httpResponseMessage.Content == null) - { - return null; - } - string jsonVmInfo = await httpResponseMessage.Content.ReadAsStringAsync(); - return JObject.Parse(jsonVmInfo).ToObject(); - } - internal static string GetHostInformation(Compute vmInformation) { return String.Concat(vmInformation?.OSType, "|", diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs new file mode 100644 index 0000000000..a0774a3c90 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -0,0 +1,136 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Telemetry +{ + using System; + using System.Collections.Generic; + using System.Net.Http; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Core.Trace; + using Microsoft.Azure.Documents; + using Newtonsoft.Json.Linq; + + /// + /// Task to collect virtual machine metadata information. using instance metedata service API. + /// ref: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows + /// Collects only application region and environment information + /// + internal class VmMetadataApiHandler : IDisposable + { + private const string DefaultVmMetadataUrL = "http://169.254.169.254/metadata/instance?api-version=2020-06-01"; + private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); + private static readonly object lockObject = new object(); + private static readonly Uri vmMetadataEndpointUrl = VmMetadataApiHandler.GetVmMetadataUrl(); + + private static VmMetadataApiHandler instance = null; + private static Uri vmMetadataUrl; + + private static volatile AzureVMMetadata azMetadata = null; + + private readonly CosmosHttpClient httpClient; + private Task apiCallTask; + + private VmMetadataApiHandler(CosmosHttpClient httpClient) + { + this.httpClient = httpClient; + this.apiCallTask = Task.Run(this.MetadataApiCallAsync, default); + } + + internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) + { + lock (VmMetadataApiHandler.lockObject) + { + if (VmMetadataApiHandler.instance == null) + { + DefaultTrace.TraceInformation("Initializing VM Metadata API "); + VmMetadataApiHandler.instance = new VmMetadataApiHandler(httpClient); + } + + return VmMetadataApiHandler.instance; + } + } + + private async Task MetadataApiCallAsync() + { + DefaultTrace.TraceInformation($"Loading VM Metadata"); + + static ValueTask CreateRequestMessage() + { + HttpRequestMessage request = new HttpRequestMessage() + { + RequestUri = vmMetadataEndpointUrl, + Method = HttpMethod.Get, + }; + request.Headers.Add("Metadata", "true"); + + return new ValueTask(request); + } + + try + { + HttpResponseMessage response = await this.httpClient + .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, + resourceType: ResourceType.Telemetry, + timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, + clientSideRequestStatistics: null, + cancellationToken: default); + azMetadata = await VmMetadataApiHandler.ProcessResponseAsync(response); + + DefaultTrace.TraceWarning("Succesfully get Instance Metedata Response : " + azMetadata.Compute.VMId); + + } + catch (Exception ex) + { + VmMetadataApiHandler.azMetadata = null; + + DefaultTrace.TraceWarning("Exception while making metadata call " + ex.ToString()); + } + + } + + internal static async Task ProcessResponseAsync(HttpResponseMessage httpResponseMessage) + { + if (httpResponseMessage.Content == null) + { + return null; + } + string jsonVmInfo = await httpResponseMessage.Content.ReadAsStringAsync(); + return JObject.Parse(jsonVmInfo).ToObject(); + } + + internal static Uri GetVmMetadataUrl() + { + if (vmMetadataUrl == null) + { + string vmMetadataUrlProp = ConfigurationManager.GetEnvironmentVariable( + ClientTelemetryOptions.EnvPropsClientTelemetryVmMetadataUrl, DefaultVmMetadataUrL); + if (!String.IsNullOrEmpty(vmMetadataUrlProp)) + { + vmMetadataUrl = new Uri(vmMetadataUrlProp); + } + + DefaultTrace.TraceInformation($"VM metadata URL for telemetry {vmMetadataUrlProp}"); + } + return vmMetadataUrl; + } + + internal static string GetMachineId() + { + return VmMetadataApiHandler.azMetadata == null ? VmMetadataApiHandler.UniqueId : VmMetadataApiHandler.azMetadata.Compute.VMId; + } + + internal static Compute GetMachineInfo() + { + return VmMetadataApiHandler.azMetadata?.Compute; + } + + public void Dispose() + { + this.apiCallTask = null; + VmMetadataApiHandler.instance = null; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs index 7aa3f9dd38..c5fe7c43af 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs @@ -83,7 +83,7 @@ private ReadOnlyMemory GetSerializedDatum() jsonTextWriter.WriteFieldName("Client Created Time Utc"); jsonTextWriter.WriteStringValue(this.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)); jsonTextWriter.WriteFieldName("MachineId"); - jsonTextWriter.WriteStringValue(ClientTelemetryHelper.GetMachineId()); + jsonTextWriter.WriteStringValue(VmMetadataApiHandler.GetMachineId()); jsonTextWriter.WriteFieldName("NumberOfClientsCreated"); jsonTextWriter.WriteNumber64Value(this.cachedNumberOfClientCreated); jsonTextWriter.WriteFieldName("NumberOfActiveClients"); diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs index e32999d04e..a9b6fe3245 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs @@ -479,7 +479,7 @@ public void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Client Configuration"); stringBuilder.AppendLine($"Client Created Time: {clientConfigurationTraceDatum.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)}"); - stringBuilder.AppendLine($"Machine Id: {ClientTelemetryHelper.GetMachineId()}"); + stringBuilder.AppendLine($"Machine Id: {VmMetadataApiHandler.GetMachineId()}"); stringBuilder.AppendLine($"Number Of Clients Created: {CosmosClient.numberOfClientsCreated}"); stringBuilder.AppendLine($"Number Of Active Clients: {CosmosClient.NumberOfActiveClients}"); stringBuilder.AppendLine($"User Agent: {clientConfigurationTraceDatum.UserAgentContainer.UserAgent}"); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 551627f191..be0f5adac2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -78,7 +78,7 @@ public void TestInitialize() return Task.FromResult(result); } - else if (request.RequestUri.AbsoluteUri.Equals(ClientTelemetryOptions.GetVmMetadataUrl().AbsoluteUri)) + else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri)) { HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); @@ -174,7 +174,7 @@ public async Task Cleanup() { await base.TestCleanup(); } - + [TestMethod] [DataRow(ConnectionMode.Direct, true)] [DataRow(ConnectionMode.Gateway, true)] @@ -182,9 +182,6 @@ public async Task Cleanup() [DataRow(ConnectionMode.Gateway, false)] public async Task PointSuccessOperationsTest(ConnectionMode mode, bool isAzureInstance) { - // Clean cached information - ClientTelemetryHelper.azMetadata = null; - Container container = await this.CreateClientAndContainer( mode: mode, isAzureInstance: isAzureInstance); @@ -691,7 +688,7 @@ public async Task CreateItemWithSubStatusCodeTest(ConnectionMode mode) return Task.FromResult(result); } - else if (request.RequestUri.AbsoluteUri.Equals(ClientTelemetryOptions.GetVmMetadataUrl().AbsoluteUri)) + else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri)) { HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 835d6ac33b..a530474a31 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -19,6 +19,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Query.Core; using Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests; + using Microsoft.Azure.Cosmos.Telemetry; using Microsoft.Azure.Cosmos.Utils; using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; @@ -88,7 +89,7 @@ public async Task InitTaskThreadSafe() { await Task.Delay(TimeSpan.FromMilliseconds(100)); } - + return null; } }; @@ -105,7 +106,7 @@ public async Task InitTaskThreadSafe() Container container = cosmosClient.GetContainer("db", "c"); - for(int loop = 0; loop < 3; loop++) + for (int loop = 0; loop < 3; loop++) { for (int i = 0; i < 10; i++) { @@ -123,7 +124,14 @@ public async Task InitTaskThreadSafe() await Task.WhenAll(tasks); - Assert.AreEqual(1, httpCallCount, "Only the first task should do the http call. All other should wait on the first task"); + if(loop == 0) + { + Assert.AreEqual(2, httpCallCount, "Only first call VM Metadata call with be made along with, Only the first task should do the http call. All other should wait on the first task"); + } + else + { + Assert.AreEqual(1, httpCallCount, "Only the first task should do the http call. All other should wait on the first task"); + } // Reset counters and retry the client to verify a new http call is done for new requests tasks.Clear(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs index ea2aa694d0..34a115e734 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs @@ -38,7 +38,7 @@ public async Task ParseAzureVMMetadataTest() string payload = JsonConvert.SerializeObject(jsonObject); result.Content = new StringContent(payload, Encoding.UTF8, "application/json"); - AzureVMMetadata metadata = await ClientTelemetryOptions.ProcessResponseAsync(result); + AzureVMMetadata metadata = await VmMetadataApiHandler.ProcessResponseAsync(result); Assert.AreEqual("eastus", metadata.Compute.Location); Assert.AreEqual("18.04-LTS", metadata.Compute.SKU); From e9b53d8229834bbc26b85febd3b7fbe1237aba05 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 26 Mar 2022 21:20:43 +0530 Subject: [PATCH 11/29] null check --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 04c63b8746..3af633791b 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -1263,7 +1263,7 @@ public void Dispose() } // Clean cached account information - this.vmMetadataApiHandler.Dispose(); + this.vmMetadataApiHandler?.Dispose(); DefaultTrace.TraceInformation("DocumentClient with id {0} disposed.", this.traceId); DefaultTrace.Flush(); From c5d97838de6db8f8c7c34f08c97f39815078552a Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 26 Mar 2022 22:30:31 +0530 Subject: [PATCH 12/29] test fix --- .../ClientTests.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index a530474a31..628f0b05b0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -79,12 +79,21 @@ public async Task ValidateExceptionOnInitTask() public async Task InitTaskThreadSafe() { int httpCallCount = 0; + int metadataCallCount = 0; bool delayCallBack = true; HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper() { RequestCallBack = async (request, cancellToken) => { - Interlocked.Increment(ref httpCallCount); + if(request.RequestUri.AbsoluteUri == VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri) + { + Interlocked.Increment(ref metadataCallCount); + } + else + { + Interlocked.Increment(ref httpCallCount); + } + while (delayCallBack) { await Task.Delay(TimeSpan.FromMilliseconds(100)); @@ -124,14 +133,8 @@ public async Task InitTaskThreadSafe() await Task.WhenAll(tasks); - if(loop == 0) - { - Assert.AreEqual(2, httpCallCount, "Only first call VM Metadata call with be made along with, Only the first task should do the http call. All other should wait on the first task"); - } - else - { - Assert.AreEqual(1, httpCallCount, "Only the first task should do the http call. All other should wait on the first task"); - } + Assert.AreEqual(1, metadataCallCount, "Only one call for VM Metadata call with be made"); + Assert.AreEqual(1, httpCallCount, "Only the first task should do the http call. All other should wait on the first task"); // Reset counters and retry the client to verify a new http call is done for new requests tasks.Clear(); From 5f721c66174c4d53bbf63f0047b67fa1b1392c42 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 26 Mar 2022 22:32:12 +0530 Subject: [PATCH 13/29] no retry for client telemetry --- Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs index b5a2a11d72..dc196a98e9 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/ClientTelemetry.cs @@ -329,7 +329,7 @@ await this.tokenProvider.AddAuthorizationHeaderAsync( using HttpResponseMessage response = await this.httpClient.SendHttpAsync(CreateRequestMessage, ResourceType.Telemetry, - HttpTimeoutPolicyDefault.Instance, + HttpTimeoutPolicyNoRetry.Instance, null, this.cancellationTokenSource.Token); From 170c3bb41cb4173c29ae548be74d6a90713f0579 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 30 Mar 2022 16:16:13 +0530 Subject: [PATCH 14/29] code refactor --- .../src/Telemetry/VmMetadataApiHandler.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index a0774a3c90..b79fc63fb3 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -41,14 +41,16 @@ private VmMetadataApiHandler(CosmosHttpClient httpClient) internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) { - lock (VmMetadataApiHandler.lockObject) + if (VmMetadataApiHandler.instance != null) { - if (VmMetadataApiHandler.instance == null) - { - DefaultTrace.TraceInformation("Initializing VM Metadata API "); - VmMetadataApiHandler.instance = new VmMetadataApiHandler(httpClient); - } + return VmMetadataApiHandler.instance; + } + lock (VmMetadataApiHandler.lockObject) + { + DefaultTrace.TraceInformation("Initializing VM Metadata API "); + VmMetadataApiHandler.instance = new VmMetadataApiHandler(httpClient); + return VmMetadataApiHandler.instance; } } @@ -111,8 +113,7 @@ internal static Uri GetVmMetadataUrl() { vmMetadataUrl = new Uri(vmMetadataUrlProp); } - - DefaultTrace.TraceInformation($"VM metadata URL for telemetry {vmMetadataUrlProp}"); + DefaultTrace.TraceInformation($"VM Metadata URL {vmMetadataUrlProp}"); } return vmMetadataUrl; } From 8c69d2540e363a1eb9375361cf545748257054d3 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 31 Mar 2022 00:17:29 +0530 Subject: [PATCH 15/29] code refactor --- .../src/Telemetry/VmMetadataApiHandler.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index b79fc63fb3..d064c12cda 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos.Telemetry using System; using System.Collections.Generic; using System.Net.Http; + using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Core.Trace; @@ -27,6 +28,7 @@ internal class VmMetadataApiHandler : IDisposable private static VmMetadataApiHandler instance = null; private static Uri vmMetadataUrl; + private static bool isInitialized = false; private static volatile AzureVMMetadata azMetadata = null; @@ -41,7 +43,7 @@ private VmMetadataApiHandler(CosmosHttpClient httpClient) internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) { - if (VmMetadataApiHandler.instance != null) + if (VmMetadataApiHandler.isInitialized) { return VmMetadataApiHandler.instance; } @@ -50,7 +52,9 @@ internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) { DefaultTrace.TraceInformation("Initializing VM Metadata API "); VmMetadataApiHandler.instance = new VmMetadataApiHandler(httpClient); - + + VmMetadataApiHandler.isInitialized = true; + return VmMetadataApiHandler.instance; } } @@ -81,14 +85,14 @@ static ValueTask CreateRequestMessage() cancellationToken: default); azMetadata = await VmMetadataApiHandler.ProcessResponseAsync(response); - DefaultTrace.TraceWarning("Succesfully get Instance Metedata Response : " + azMetadata.Compute.VMId); + DefaultTrace.TraceWarning($"Succesfully get Instance Metedata Response : {azMetadata.Compute.VMId}"); } catch (Exception ex) { - VmMetadataApiHandler.azMetadata = null; + DefaultTrace.TraceWarning($"Exception while making metadata call {ex}"); - DefaultTrace.TraceWarning("Exception while making metadata call " + ex.ToString()); + this.Dispose(); } } @@ -132,6 +136,7 @@ public void Dispose() { this.apiCallTask = null; VmMetadataApiHandler.instance = null; + VmMetadataApiHandler.isInitialized = false; } } } From bd8eb8f0156fae677bad7a6a09172178e4259b04 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 31 Mar 2022 02:01:14 +0530 Subject: [PATCH 16/29] retry tests --- .../CosmosHttpClientCoreTests.cs | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 92ab625e9d..259f6b1727 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -133,6 +133,9 @@ public void VerifyShouldRetryOnResponseTest() Assert.IsFalse(HttpTimeoutPolicyDefault.Instance.ShouldRetryBasedOnResponse(HttpMethod.Put, responseMessage)); Assert.IsFalse(HttpTimeoutPolicyControlPlaneRead.Instance.ShouldRetryBasedOnResponse(HttpMethod.Put, responseMessage)); + Assert.IsFalse(HttpTimeoutPolicyNoRetry.Instance.ShouldRetryBasedOnResponse(HttpMethod.Put, responseMessage)); + Assert.IsFalse(HttpTimeoutPolicyNoRetry.Instance.ShouldRetryBasedOnResponse(HttpMethod.Get, responseMessage)); + if (statusCode == HttpStatusCode.RequestTimeout) { Assert.IsTrue(HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance.ShouldRetryBasedOnResponse(HttpMethod.Get, responseMessage)); @@ -222,6 +225,74 @@ async Task sendFunc(HttpRequestMessage request, Cancellatio Assert.AreEqual(HttpStatusCode.RequestTimeout, responseMessage.StatusCode, "Should be a request timeout"); } + [TestMethod] + public async Task Retry3TimesOnDefaultPolicyTestAsync() + { + int count = 0; + async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + { + count++; + + throw new OperationCanceledException("API with exception"); + + } + + DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + using CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + + try + { + HttpResponseMessage responseMessage = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))), + resourceType: ResourceType.Collection, + timeoutPolicy: HttpTimeoutPolicyDefault.Instance, + clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow), + cancellationToken: default); + } + catch (Exception ex) + { + //Ignore the exception + } + + Assert.AreEqual(3, count, "Should retry 3 times"); + } + + [TestMethod] + public async Task NoRetryOnNoRetryPolicyTestAsync() + { + int count = 0; + async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + { + count++; + + throw new OperationCanceledException("API with exception"); + + } + + DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + using CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + + try + { + HttpResponseMessage responseMessage = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))), + resourceType: ResourceType.Collection, + timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, + clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow), + cancellationToken: default); + } + catch (Exception ex) + { + //Ignore the exception + } + + Assert.AreEqual(1, count, "Should not retry at all"); + } + [TestMethod] public async Task RetryTransientIssuesForQueryPlanTestAsync() { From 5131754f1adb6e97129ce032872bf7fd2e83a2e9 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 31 Mar 2022 22:24:34 +0530 Subject: [PATCH 17/29] code refcator --- .../src/Telemetry/VmMetadataApiHandler.cs | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index d064c12cda..76e3cc0441 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -5,10 +5,7 @@ namespace Microsoft.Azure.Cosmos.Telemetry { using System; - using System.Collections.Generic; using System.Net.Http; - using System.Runtime.CompilerServices; - using System.Text; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Core.Trace; using Microsoft.Azure.Documents; @@ -27,10 +24,10 @@ internal class VmMetadataApiHandler : IDisposable private static readonly Uri vmMetadataEndpointUrl = VmMetadataApiHandler.GetVmMetadataUrl(); private static VmMetadataApiHandler instance = null; - private static Uri vmMetadataUrl; + private static Uri vmMetadataUrl = null; private static bool isInitialized = false; - private static volatile AzureVMMetadata azMetadata = null; + private static AzureVMMetadata azMetadata = null; private readonly CosmosHttpClient httpClient; private Task apiCallTask; @@ -38,7 +35,11 @@ internal class VmMetadataApiHandler : IDisposable private VmMetadataApiHandler(CosmosHttpClient httpClient) { this.httpClient = httpClient; - this.apiCallTask = Task.Run(this.MetadataApiCallAsync, default); + + this.apiCallTask = Task.Run(this.MetadataApiCallAsync, default) + .ContinueWith(t => DefaultTrace.TraceWarning( + $"Exception while making metadata call {t.Exception}"), + TaskContinuationOptions.OnlyOnFaulted); } internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) @@ -75,26 +76,16 @@ static ValueTask CreateRequestMessage() return new ValueTask(request); } - try - { - HttpResponseMessage response = await this.httpClient - .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, - resourceType: ResourceType.Telemetry, - timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, - clientSideRequestStatistics: null, - cancellationToken: default); - azMetadata = await VmMetadataApiHandler.ProcessResponseAsync(response); - - DefaultTrace.TraceWarning($"Succesfully get Instance Metedata Response : {azMetadata.Compute.VMId}"); + HttpResponseMessage response = await this.httpClient + .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, + resourceType: ResourceType.Telemetry, + timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, + clientSideRequestStatistics: null, + cancellationToken: default); - } - catch (Exception ex) - { - DefaultTrace.TraceWarning($"Exception while making metadata call {ex}"); - - this.Dispose(); - } + azMetadata = await VmMetadataApiHandler.ProcessResponseAsync(response); + DefaultTrace.TraceInformation($"Succesfully get Instance Metadata Response : {azMetadata.Compute.VMId}"); } internal static async Task ProcessResponseAsync(HttpResponseMessage httpResponseMessage) @@ -134,8 +125,12 @@ internal static Compute GetMachineInfo() public void Dispose() { + this.apiCallTask?.Dispose(); + this.apiCallTask = null; VmMetadataApiHandler.instance = null; + VmMetadataApiHandler.azMetadata = null; + VmMetadataApiHandler.isInitialized = false; } } From d64affd50e3fb825d95e0b459cb4140bd33f829c Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Fri, 1 Apr 2022 01:08:59 +0530 Subject: [PATCH 18/29] add documentation --- .../src/Telemetry/VmMetadataApiHandler.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 76e3cc0441..2fc5990f16 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -113,20 +113,29 @@ internal static Uri GetVmMetadataUrl() return vmMetadataUrl; } + /// + /// Get VM Id if it is Azure System else Generate an unique id for this machine + /// + /// machine id internal static string GetMachineId() { return VmMetadataApiHandler.azMetadata == null ? VmMetadataApiHandler.UniqueId : VmMetadataApiHandler.azMetadata.Compute.VMId; } + /// + /// Get Machine Information (If Azure System) else null + /// + /// Compute internal static Compute GetMachineInfo() { return VmMetadataApiHandler.azMetadata?.Compute; } + /// + /// Clean up cached values + /// public void Dispose() { - this.apiCallTask?.Dispose(); - this.apiCallTask = null; VmMetadataApiHandler.instance = null; VmMetadataApiHandler.azMetadata = null; From 2915bbd19569aa6c1480fe7c9faa15ab3169597c Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Fri, 1 Apr 2022 21:45:44 +0530 Subject: [PATCH 19/29] remove dispose in vmhandler --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 3 -- .../src/Telemetry/VmMetadataApiHandler.cs | 34 ++++--------------- .../ClientTelemetryTests.cs | 5 +-- .../ClientTests.cs | 2 +- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 3af633791b..a0dcb3b467 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -1262,9 +1262,6 @@ public void Dispose() this.initTaskCache = null; } - // Clean cached account information - this.vmMetadataApiHandler?.Dispose(); - DefaultTrace.TraceInformation("DocumentClient with id {0} disposed.", this.traceId); DefaultTrace.Flush(); diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 2fc5990f16..44186df015 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -16,27 +16,25 @@ namespace Microsoft.Azure.Cosmos.Telemetry /// ref: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows /// Collects only application region and environment information /// - internal class VmMetadataApiHandler : IDisposable + internal class VmMetadataApiHandler { - private const string DefaultVmMetadataUrL = "http://169.254.169.254/metadata/instance?api-version=2020-06-01"; + internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); + private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); private static readonly object lockObject = new object(); - private static readonly Uri vmMetadataEndpointUrl = VmMetadataApiHandler.GetVmMetadataUrl(); private static VmMetadataApiHandler instance = null; - private static Uri vmMetadataUrl = null; private static bool isInitialized = false; private static AzureVMMetadata azMetadata = null; private readonly CosmosHttpClient httpClient; - private Task apiCallTask; private VmMetadataApiHandler(CosmosHttpClient httpClient) { this.httpClient = httpClient; - this.apiCallTask = Task.Run(this.MetadataApiCallAsync, default) + _ = Task.Run(this.MetadataApiCallAsync, default) .ContinueWith(t => DefaultTrace.TraceWarning( $"Exception while making metadata call {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted); @@ -68,7 +66,7 @@ static ValueTask CreateRequestMessage() { HttpRequestMessage request = new HttpRequestMessage() { - RequestUri = vmMetadataEndpointUrl, + RequestUri = VmMetadataApiHandler.vmMetadataEndpointUrl, Method = HttpMethod.Get, }; request.Headers.Add("Metadata", "true"); @@ -98,21 +96,6 @@ internal static async Task ProcessResponseAsync(HttpResponseMes return JObject.Parse(jsonVmInfo).ToObject(); } - internal static Uri GetVmMetadataUrl() - { - if (vmMetadataUrl == null) - { - string vmMetadataUrlProp = ConfigurationManager.GetEnvironmentVariable( - ClientTelemetryOptions.EnvPropsClientTelemetryVmMetadataUrl, DefaultVmMetadataUrL); - if (!String.IsNullOrEmpty(vmMetadataUrlProp)) - { - vmMetadataUrl = new Uri(vmMetadataUrlProp); - } - DefaultTrace.TraceInformation($"VM Metadata URL {vmMetadataUrlProp}"); - } - return vmMetadataUrl; - } - /// /// Get VM Id if it is Azure System else Generate an unique id for this machine /// @@ -132,14 +115,11 @@ internal static Compute GetMachineInfo() } /// - /// Clean up cached values + /// Only for tests, as this cache needs to clear while switching between Azure System tests and non Azure system tests /// - public void Dispose() + internal static void Clear() { - this.apiCallTask = null; - VmMetadataApiHandler.instance = null; VmMetadataApiHandler.azMetadata = null; - VmMetadataApiHandler.isInitialized = false; } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index be0f5adac2..899afafd77 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -78,7 +78,7 @@ public void TestInitialize() return Task.FromResult(result); } - else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri)) + else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.vmMetadataEndpointUrl.AbsoluteUri)) { HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); @@ -172,6 +172,7 @@ private static void ResetSystemUsageMonitor(bool isTelemetryEnabled) [TestCleanup] public async Task Cleanup() { + VmMetadataApiHandler.Clear(); await base.TestCleanup(); } @@ -688,7 +689,7 @@ public async Task CreateItemWithSubStatusCodeTest(ConnectionMode mode) return Task.FromResult(result); } - else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri)) + else if (request.RequestUri.AbsoluteUri.Equals(VmMetadataApiHandler.vmMetadataEndpointUrl.AbsoluteUri)) { HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 628f0b05b0..21e9ed605b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -85,7 +85,7 @@ public async Task InitTaskThreadSafe() { RequestCallBack = async (request, cancellToken) => { - if(request.RequestUri.AbsoluteUri == VmMetadataApiHandler.GetVmMetadataUrl().AbsoluteUri) + if(request.RequestUri.AbsoluteUri == VmMetadataApiHandler.vmMetadataEndpointUrl.AbsoluteUri) { Interlocked.Increment(ref metadataCallCount); } From 157c585f38d947a869bd0663e11785d54441fa5b Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 2 Apr 2022 02:49:18 +0530 Subject: [PATCH 20/29] hashedMachineId and add test --- .../src/Authorization/StringHMACSHA256Hash.cs | 5 ++ .../src/Telemetry/VmMetadataApiHandler.cs | 40 +++++++++- .../ClientTelemetryTests.cs | 1 - .../VmMetadataApiHandlerTest.cs | 75 +++++++++++++++++++ 4 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs diff --git a/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs b/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs index baba6db57a..d8efbde9d4 100644 --- a/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs +++ b/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs @@ -45,6 +45,11 @@ public byte[] ComputeHash(ArraySegment bytesToHash) } } + internal string ComputeHash(string machineName) + { + throw new NotImplementedException(); + } + public SecureString Key { get diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 44186df015..6c8dea2402 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -6,6 +6,8 @@ namespace Microsoft.Azure.Cosmos.Telemetry { using System; using System.Net.Http; + using System.Security.Cryptography; + using System.Text; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Core.Trace; using Microsoft.Azure.Documents; @@ -21,6 +23,8 @@ internal class VmMetadataApiHandler internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); + private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeSha256Hash(Environment.MachineName); + private static readonly object lockObject = new object(); private static VmMetadataApiHandler instance = null; @@ -97,12 +101,26 @@ internal static async Task ProcessResponseAsync(HttpResponseMes } /// - /// Get VM Id if it is Azure System else Generate an unique id for this machine + /// Get VM Id if it is Azure System + /// else Get Hashed MachineName + /// else Generate an unique id for this machine/process /// /// machine id internal static string GetMachineId() { - return VmMetadataApiHandler.azMetadata == null ? VmMetadataApiHandler.UniqueId : VmMetadataApiHandler.azMetadata.Compute.VMId; + if (VmMetadataApiHandler.azMetadata != null) + { + return VmMetadataApiHandler.azMetadata.Compute.VMId; + } + + try + { + return VmMetadataApiHandler.HashedMachineName; + } + catch (Exception) + { + return VmMetadataApiHandler.UniqueId; + } } /// @@ -114,6 +132,24 @@ internal static Compute GetMachineInfo() return VmMetadataApiHandler.azMetadata?.Compute; } + internal static string ComputeSha256Hash(string rawData) + { + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) + { + // ComputeHash - returns byte array + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + + // Convert byte array to a string + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i++) + { + builder.Append(bytes[i].ToString("x2")); + } + return builder.ToString(); + } + } + /// /// Only for tests, as this cache needs to clear while switching between Azure System tests and non Azure system tests /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 899afafd77..3997d53eb9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -946,7 +946,6 @@ private static void AssertAccountLevelInformation( else { Assert.AreNotEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", machineId.ToList()[0]); - Assert.IsTrue(machineId.ToList()[0].Contains("uuid:"), machineId.ToList()[0]); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs new file mode 100644 index 0000000000..2380820b50 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -0,0 +1,75 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Net; + using System.Net.Http; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Telemetry; + using Microsoft.Azure.Cosmos.Tests; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + + [TestClass] + public class VmMetadataApiHandlerTest + { + [TestMethod] + public async Task GetVmIdAsMachineIdTest() + { + static Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + { + object jsonObject = JsonConvert.DeserializeObject("{\"compute\":{\"azEnvironment\":\"AzurePublicCloud\",\"customData\":\"\",\"isHostCompatibilityLayerVm\":\"false\",\"licenseType\":\"\",\"location\":\"eastus\",\"name\":\"sourabh-testing\",\"offer\":\"UbuntuServer\",\"osProfile\":{\"adminUsername\":\"azureuser\",\"computerName\":\"sourabh-testing\"},\"osType\":\"Linux\",\"placementGroupId\":\"\",\"plan\":{\"name\":\"\",\"product\":\"\",\"publisher\":\"\"},\"platformFaultDomain\":\"0\",\"platformUpdateDomain\":\"0\",\"provider\":\"Microsoft.Compute\",\"publicKeys\":[{\"keyData\":\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5uCeOAm3ehmhI+2PbMoMl17Eo\r\nqfHKCycSaBJsv9qxlmBOuFheSJc1XknJleXUSsuTO016/d1PyWpevnqOZNRksWoa\r\nJvQ23sDTxcK+X2OP3QlCUeX4cMjPXqlL8z1UYzU4Bx3fFvf8fs67G3N72sxWBw5P\r\nZyuXyhBm0NCe/2NYMKgEDT4ma8XszO0ikbhoPKbMbgHAQk/ktWQHNcqYOPQKEWqp\r\nEK1R0rjS2nmtovfScP/ZGXcvOpJ1/NDBo4dh1K+OxOGM/4PSH/F448J5Zy4eAyEk\r\nscys+IpeIOTOlRUy/703SNIX0LEWlnYqbyL9c1ypcYLQqF76fKkDfzzFI/OWVlGw\r\nhj/S9uP8iMsR+fhGIbn6MAa7O4DWPWLuedSp7KDYyjY09gqNJsfuaAJN4LiC6bPy\r\nhknm0PVLK3ux7EUOt+cZrHCdIFWbdOtxiPNIl1tkv9kV5aE5Aj2gJm4MeB9uXYhS\r\nOuksboBc0wyUGrl9+XZJ1+NlZOf7IjVi86CieK8= generated-by-azure\r\n\",\"path\":\"/home/azureuser/.ssh/authorized_keys\"}],\"publisher\":\"Canonical\",\"resourceGroupName\":\"sourabh-telemetry-sdk\",\"resourceId\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/virtualMachines/sourabh-testing\",\"securityProfile\":{\"secureBootEnabled\":\"false\",\"virtualTpmEnabled\":\"false\"},\"sku\":\"18.04-LTS\",\"storageProfile\":{\"dataDisks\":[],\"imageReference\":{\"id\":\"\",\"offer\":\"UbuntuServer\",\"publisher\":\"Canonical\",\"sku\":\"18.04-LTS\",\"version\":\"latest\"},\"osDisk\":{\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\",\"diffDiskSettings\":{\"option\":\"\"},\"diskSizeGB\":\"30\",\"encryptionSettings\":{\"enabled\":\"false\"},\"image\":{\"uri\":\"\"},\"managedDisk\":{\"id\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/disks/sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"storageAccountType\":\"Premium_LRS\"},\"name\":\"sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"osType\":\"Linux\",\"vhd\":{\"uri\":\"\"},\"writeAcceleratorEnabled\":\"false\"}},\"subscriptionId\":\"8fba6d4f-7c37-4d13-9063-fd58ad2b86e2\",\"tags\":\"azsecpack:nonprod;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true\",\"tagsList\":[{\"name\":\"azsecpack\",\"value\":\"nonprod\"},{\"name\":\"platformsettings.host_environment.service.platform_optedin_for_rootcerts\",\"value\":\"true\"}],\"version\":\"18.04.202103250\",\"vmId\":\"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd\",\"vmScaleSetName\":\"\",\"vmSize\":\"Standard_D2s_v3\",\"zone\":\"1\"},\"network\":{\"interface\":[{\"ipv4\":{\"ipAddress\":[{\"privateIpAddress\":\"10.0.7.5\",\"publicIpAddress\":\"\"}],\"subnet\":[{\"address\":\"10.0.7.0\",\"prefix\":\"24\"}]},\"ipv6\":{\"ipAddress\":[]},\"macAddress\":\"000D3A8F8BA0\"}]}}"); + string payload = JsonConvert.SerializeObject(jsonObject); + HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(payload, Encoding.UTF8, "application/json") + }; + return Task.FromResult(response); + } + + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + + VmMetadataApiHandler.Initialize(cosmoshttpClient); + + await Task.Delay(2000); + Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", VmMetadataApiHandler.GetMachineId()); + } + + [TestMethod] + public async Task GetHashedMachineNameAsMachineIdTest() + { + string expectedMachineId = "hashedMachineName:" + VmMetadataApiHandler.ComputeSha256Hash(Environment.MachineName); + + static Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) { throw new Exception("error while making API call"); }; + + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + + VmMetadataApiHandler.Initialize(cosmoshttpClient); + + await Task.Delay(2000); + Assert.AreEqual(expectedMachineId, VmMetadataApiHandler.GetMachineId()); + } + + private class MockMessageHandler : HttpMessageHandler + { + private readonly Func> sendFunc; + + public MockMessageHandler(Func> func) + { + this.sendFunc = func; + } + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await this.sendFunc(request, cancellationToken); + } + } + } +} From 3e1126455db70200e657d4afd723d833da62ac28 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Sat, 2 Apr 2022 02:53:31 +0530 Subject: [PATCH 21/29] sha1 --- .../src/Authorization/StringHMACSHA256Hash.cs | 5 ----- .../src/Telemetry/VmMetadataApiHandler.cs | 15 ++++++++++----- .../VmMetadataApiHandlerTest.cs | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs b/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs index d8efbde9d4..baba6db57a 100644 --- a/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs +++ b/Microsoft.Azure.Cosmos/src/Authorization/StringHMACSHA256Hash.cs @@ -45,11 +45,6 @@ public byte[] ComputeHash(ArraySegment bytesToHash) } } - internal string ComputeHash(string machineName) - { - throw new NotImplementedException(); - } - public SecureString Key { get diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 6c8dea2402..6f87d21e05 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -23,7 +23,7 @@ internal class VmMetadataApiHandler internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); - private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeSha256Hash(Environment.MachineName); + private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); private static readonly object lockObject = new object(); @@ -132,13 +132,18 @@ internal static Compute GetMachineInfo() return VmMetadataApiHandler.azMetadata?.Compute; } - internal static string ComputeSha256Hash(string rawData) + /// + /// Hash a passed Value + /// + /// + /// hashed Value + internal static string ComputeHash(string rawData) { - // Create a SHA256 - using (SHA256 sha256Hash = SHA256.Create()) + // Create a SHA1 + using (SHA1 sha1Hash = SHA1.Create()) { // ComputeHash - returns byte array - byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + byte[] bytes = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); // Convert byte array to a string StringBuilder builder = new StringBuilder(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 2380820b50..8ca603d4c5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -45,7 +45,7 @@ static Task sendFunc(HttpRequestMessage request, Cancellati [TestMethod] public async Task GetHashedMachineNameAsMachineIdTest() { - string expectedMachineId = "hashedMachineName:" + VmMetadataApiHandler.ComputeSha256Hash(Environment.MachineName); + string expectedMachineId = "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); static Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) { throw new Exception("error while making API call"); }; From a0684fd20a71f482730417329317803ebfd66cfa Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Mon, 4 Apr 2022 15:22:07 +0530 Subject: [PATCH 22/29] vm clear --- .../Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs | 3 +++ .../VmMetadataApiHandlerTest.cs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 21e9ed605b..a9bcd8193c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -81,6 +81,9 @@ public async Task InitTaskThreadSafe() int httpCallCount = 0; int metadataCallCount = 0; bool delayCallBack = true; + + VmMetadataApiHandler.Clear(); + HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper() { RequestCallBack = async (request, cancellToken) => diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 8ca603d4c5..7bc3f416cf 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -19,6 +19,12 @@ namespace Microsoft.Azure.Cosmos [TestClass] public class VmMetadataApiHandlerTest { + [TestCleanup] + public void Cleanp() + { + VmMetadataApiHandler.Clear(); + } + [TestMethod] public async Task GetVmIdAsMachineIdTest() { From ba53f3924fc9f529c68eddb400d0b55d09ee0035 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Mon, 4 Apr 2022 16:31:54 +0530 Subject: [PATCH 23/29] test intitliz add --- .../Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 7bc3f416cf..18e6a4be8b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -19,8 +19,8 @@ namespace Microsoft.Azure.Cosmos [TestClass] public class VmMetadataApiHandlerTest { - [TestCleanup] - public void Cleanp() + [TestInitialize] + public void Intialize() { VmMetadataApiHandler.Clear(); } From 219983780d82613b71ac732659de774f0f665442 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 6 Apr 2022 18:40:50 +0530 Subject: [PATCH 24/29] intilize to try initilize --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 4 +- .../src/Telemetry/VmMetadataApiHandler.cs | 45 +++++++------------ .../VmMetadataApiHandlerTest.cs | 4 +- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index a0dcb3b467..5ca675e1ce 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -174,8 +174,6 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private event EventHandler receivedResponse; private Func transportClientHandlerFactory; - private VmMetadataApiHandler vmMetadataApiHandler; - /// /// Initializes a new instance of the class using the /// specified Azure Cosmos DB service endpoint, key, and connection policy for the Azure Cosmos DB service. @@ -901,7 +899,7 @@ internal virtual void Initialize(Uri serviceEndpoint, this.receivedResponse); // Loading VM Information (non blocking call and initialization won't fail if this call fails) - this.vmMetadataApiHandler = VmMetadataApiHandler.Initialize(this.httpClient); + VmMetadataApiHandler.TryInitialize(this.httpClient); if (sessionContainer != null) { diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 6f87d21e05..9dd34e70ac 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -21,48 +21,37 @@ namespace Microsoft.Azure.Cosmos.Telemetry internal class VmMetadataApiHandler { internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); - + private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); - private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); - private static readonly object lockObject = new object(); - private static VmMetadataApiHandler instance = null; - private static bool isInitialized = false; + private static CosmosHttpClient httpClient; + private static bool isInitialized = false; private static AzureVMMetadata azMetadata = null; + private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); - private readonly CosmosHttpClient httpClient; - - private VmMetadataApiHandler(CosmosHttpClient httpClient) - { - this.httpClient = httpClient; - - _ = Task.Run(this.MetadataApiCallAsync, default) - .ContinueWith(t => DefaultTrace.TraceWarning( - $"Exception while making metadata call {t.Exception}"), - TaskContinuationOptions.OnlyOnFaulted); - } - - internal static VmMetadataApiHandler Initialize(CosmosHttpClient httpClient) + internal static void TryInitialize(CosmosHttpClient httpClient) { - if (VmMetadataApiHandler.isInitialized) - { - return VmMetadataApiHandler.instance; - } + VmMetadataApiHandler.httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); lock (VmMetadataApiHandler.lockObject) { - DefaultTrace.TraceInformation("Initializing VM Metadata API "); - VmMetadataApiHandler.instance = new VmMetadataApiHandler(httpClient); + if (!VmMetadataApiHandler.isInitialized) + { + DefaultTrace.TraceInformation("Initializing VM Metadata API "); - VmMetadataApiHandler.isInitialized = true; + VmMetadataApiHandler.isInitialized = true; + + _ = Task.Run(MetadataApiCallAsync, default) + .ContinueWith(t => DefaultTrace.TraceWarning($"Exception while making metadata call {t.Exception}"), + TaskContinuationOptions.OnlyOnFaulted); + } - return VmMetadataApiHandler.instance; } } - private async Task MetadataApiCallAsync() + private static async Task MetadataApiCallAsync() { DefaultTrace.TraceInformation($"Loading VM Metadata"); @@ -78,7 +67,7 @@ static ValueTask CreateRequestMessage() return new ValueTask(request); } - HttpResponseMessage response = await this.httpClient + HttpResponseMessage response = await VmMetadataApiHandler.httpClient .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, resourceType: ResourceType.Telemetry, timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 18e6a4be8b..03c9ff5c6b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -42,7 +42,7 @@ static Task sendFunc(HttpRequestMessage request, Cancellati HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); - VmMetadataApiHandler.Initialize(cosmoshttpClient); + VmMetadataApiHandler.TryInitialize(cosmoshttpClient); await Task.Delay(2000); Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", VmMetadataApiHandler.GetMachineId()); @@ -58,7 +58,7 @@ public async Task GetHashedMachineNameAsMachineIdTest() HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); - VmMetadataApiHandler.Initialize(cosmoshttpClient); + VmMetadataApiHandler.TryInitialize(cosmoshttpClient); await Task.Delay(2000); Assert.AreEqual(expectedMachineId, VmMetadataApiHandler.GetMachineId()); From 3f219055bf8741d599278280b88cb5c1bdf0f730 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 7 Apr 2022 00:13:52 +0530 Subject: [PATCH 25/29] conflict resolve --- .../ClientTelemetryTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index 3997d53eb9..b0dce907f2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -811,7 +811,7 @@ private async Task WaitAndAssert( actualOperationList: actualOperationList, expectedSubstatuscode: expectedSubstatuscode); - ClientTelemetryTests.AssertSystemLevelInformation(actualSystemInformation); + ClientTelemetryTests.AssertSystemLevelInformation(actualSystemInformation, this.expectedMetricNameUnitMap); } private static void AssertSystemLevelInformation(List actualSystemInformation, IDictionary expectedMetricNameUnitMap) From 3babee07a8dbe81dd56f7b41e94c3ef285d594c2 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 7 Apr 2022 01:30:23 +0530 Subject: [PATCH 26/29] code refactor --- .../src/Telemetry/VmMetadataApiHandler.cs | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 9dd34e70ac..0cf0408230 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -18,40 +18,44 @@ namespace Microsoft.Azure.Cosmos.Telemetry /// ref: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows /// Collects only application region and environment information /// - internal class VmMetadataApiHandler + internal static class VmMetadataApiHandler { internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); - private static readonly object lockObject = new object(); + private static readonly string HashedMachineName = "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); - private static CosmosHttpClient httpClient; + private static readonly object lockObject = new object(); private static bool isInitialized = false; private static AzureVMMetadata azMetadata = null; - private static string HashedMachineName => "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); - + internal static void TryInitialize(CosmosHttpClient httpClient) { - VmMetadataApiHandler.httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); + if (VmMetadataApiHandler.isInitialized) + { + return; + } lock (VmMetadataApiHandler.lockObject) { - if (!VmMetadataApiHandler.isInitialized) + if (VmMetadataApiHandler.isInitialized) { - DefaultTrace.TraceInformation("Initializing VM Metadata API "); + return; + } - VmMetadataApiHandler.isInitialized = true; + DefaultTrace.TraceInformation("Initializing VM Metadata API "); - _ = Task.Run(MetadataApiCallAsync, default) - .ContinueWith(t => DefaultTrace.TraceWarning($"Exception while making metadata call {t.Exception}"), - TaskContinuationOptions.OnlyOnFaulted); - } + VmMetadataApiHandler.isInitialized = true; + + _ = Task.Run(() => MetadataApiCallAsync(httpClient), default) + .ContinueWith(t => DefaultTrace.TraceWarning($"Exception while making metadata call {t.Exception}"), + TaskContinuationOptions.OnlyOnFaulted); } } - private static async Task MetadataApiCallAsync() + private static async Task MetadataApiCallAsync(CosmosHttpClient httpClient) { DefaultTrace.TraceInformation($"Loading VM Metadata"); @@ -67,7 +71,7 @@ static ValueTask CreateRequestMessage() return new ValueTask(request); } - HttpResponseMessage response = await VmMetadataApiHandler.httpClient + HttpResponseMessage response = await httpClient .SendHttpAsync(createRequestMessageAsync: CreateRequestMessage, resourceType: ResourceType.Telemetry, timeoutPolicy: HttpTimeoutPolicyNoRetry.Instance, @@ -128,11 +132,11 @@ internal static Compute GetMachineInfo() /// hashed Value internal static string ComputeHash(string rawData) { - // Create a SHA1 - using (SHA1 sha1Hash = SHA1.Create()) + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) { // ComputeHash - returns byte array - byte[] bytes = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); // Convert byte array to a string StringBuilder builder = new StringBuilder(); @@ -144,13 +148,10 @@ internal static string ComputeHash(string rawData) } } - /// - /// Only for tests, as this cache needs to clear while switching between Azure System tests and non Azure system tests - /// internal static void Clear() { VmMetadataApiHandler.azMetadata = null; - VmMetadataApiHandler.isInitialized = false; + VmMetadataApiHandler.isInitialized = false; } } } From 98ebd6b82b992489656d3f65e84f5187f8d28955 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 7 Apr 2022 15:04:44 +0530 Subject: [PATCH 27/29] clear cache using reflection --- .../src/Telemetry/VmMetadataApiHandler.cs | 5 ----- .../ClientTelemetryTests.cs | 11 ++++++++++- .../ClientTests.cs | 10 +++++++++- .../VmMetadataApiHandlerTest.cs | 11 ++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 0cf0408230..b15fe1d24f 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -148,10 +148,5 @@ internal static string ComputeHash(string rawData) } } - internal static void Clear() - { - VmMetadataApiHandler.azMetadata = null; - VmMetadataApiHandler.isInitialized = false; - } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs index b0dce907f2..1393198305 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTelemetryTests.cs @@ -172,7 +172,16 @@ private static void ResetSystemUsageMonitor(bool isTelemetryEnabled) [TestCleanup] public async Task Cleanup() { - VmMetadataApiHandler.Clear(); + var isInitializedField = typeof(VmMetadataApiHandler).GetField("isInitialized", + BindingFlags.Static | + BindingFlags.NonPublic); + isInitializedField.SetValue(null, false); + + var azMetadataField = typeof(VmMetadataApiHandler).GetField("azMetadata", + BindingFlags.Static | + BindingFlags.NonPublic); + azMetadataField.SetValue(null, null); + await base.TestCleanup(); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index a9bcd8193c..0b2d129247 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -82,7 +82,15 @@ public async Task InitTaskThreadSafe() int metadataCallCount = 0; bool delayCallBack = true; - VmMetadataApiHandler.Clear(); + var isInitializedField = typeof(VmMetadataApiHandler).GetField("isInitialized", + BindingFlags.Static | + BindingFlags.NonPublic); + isInitializedField.SetValue(null, false); + + var azMetadataField = typeof(VmMetadataApiHandler).GetField("azMetadata", + BindingFlags.Static | + BindingFlags.NonPublic); + azMetadataField.SetValue(null, null); HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper() { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 03c9ff5c6b..88e27d0638 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos using System; using System.Net; using System.Net.Http; + using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -22,7 +23,15 @@ public class VmMetadataApiHandlerTest [TestInitialize] public void Intialize() { - VmMetadataApiHandler.Clear(); + var isInitializedField = typeof(VmMetadataApiHandler).GetField("isInitialized", + BindingFlags.Static | + BindingFlags.NonPublic); + isInitializedField.SetValue(null, false); + + var azMetadataField = typeof(VmMetadataApiHandler).GetField("azMetadata", + BindingFlags.Static | + BindingFlags.NonPublic); + azMetadataField.SetValue(null, null); } [TestMethod] From 2c1a10076c6472c70b526b4aa2fd221ccdf6cc1f Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 7 Apr 2022 22:32:42 +0530 Subject: [PATCH 28/29] lazy hashed machine name --- .../src/Telemetry/VmMetadataApiHandler.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index b15fe1d24f..08ea830499 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -22,9 +22,6 @@ internal static class VmMetadataApiHandler { internal static readonly Uri vmMetadataEndpointUrl = new ("http://169.254.169.254/metadata/instance?api-version=2020-06-01"); - private static readonly string UniqueId = "uuid:" + Guid.NewGuid().ToString(); - private static readonly string HashedMachineName = "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); - private static readonly object lockObject = new object(); private static bool isInitialized = false; @@ -106,14 +103,7 @@ internal static string GetMachineId() return VmMetadataApiHandler.azMetadata.Compute.VMId; } - try - { - return VmMetadataApiHandler.HashedMachineName; - } - catch (Exception) - { - return VmMetadataApiHandler.UniqueId; - } + return VmMetadataApiHandler.uniqueId.Value; } /// @@ -148,5 +138,19 @@ internal static string ComputeHash(string rawData) } } + private static readonly Lazy uniqueId = new Lazy(() => + { + try + { + return "hashedMachineName:" + VmMetadataApiHandler.ComputeHash(Environment.MachineName); + } + catch (Exception ex) + { + DefaultTrace.TraceWarning("Error while generating hashed machine name " + ex.Message); + } + + return "uuid:" + Guid.NewGuid().ToString(); + }); + } } From cd19391ac48f245356586a2873aecfd314f8be4a Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Fri, 8 Apr 2022 01:20:20 +0530 Subject: [PATCH 29/29] hash value --- .../src/Telemetry/VmMetadataApiHandler.cs | 13 ++++---- .../ClientTelemetryTests.cs | 23 +------------- .../VmMetadataApiHandlerTest.cs | 30 +++++++++++++++++++ 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs index 08ea830499..369e6f0963 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs @@ -122,19 +122,20 @@ internal static Compute GetMachineInfo() /// hashed Value internal static string ComputeHash(string rawData) { + if (string.IsNullOrEmpty(rawData)) + { + throw new ArgumentNullException(nameof(rawData)); + } + // Create a SHA256 using (SHA256 sha256Hash = SHA256.Create()) { // ComputeHash - returns byte array byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + Array.Resize(ref bytes, 16); // Convert byte array to a string - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < bytes.Length; i++) - { - builder.Append(bytes[i].ToString("x2")); - } - return builder.ToString(); + return new Guid(bytes).ToString(); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs index 34a115e734..c2434953ed 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientTelemetryTests.cs @@ -14,6 +14,7 @@ namespace Microsoft.Azure.Cosmos.Tests using Newtonsoft.Json; using Microsoft.Azure.Cosmos.Telemetry; using System.Collections.Generic; + using System.Xml.Serialization; /// /// Tests for . @@ -27,27 +28,6 @@ public void Cleanup() Environment.SetEnvironmentVariable(ClientTelemetryOptions.EnvPropsClientTelemetryEnabled, null); } - [TestMethod] - public async Task ParseAzureVMMetadataTest() - { - HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); - - // Add a substatus code that is not part of the enum. - // This ensures that if the backend adds a enum the status code is not lost. - object jsonObject = JsonConvert.DeserializeObject("{\"compute\":{\"azEnvironment\":\"AzurePublicCloud\",\"customData\":\"\",\"isHostCompatibilityLayerVm\":\"false\",\"licenseType\":\"\",\"location\":\"eastus\",\"name\":\"sourabh-testing\",\"offer\":\"UbuntuServer\",\"osProfile\":{\"adminUsername\":\"azureuser\",\"computerName\":\"sourabh-testing\"},\"osType\":\"Linux\",\"placementGroupId\":\"\",\"plan\":{\"name\":\"\",\"product\":\"\",\"publisher\":\"\"},\"platformFaultDomain\":\"0\",\"platformUpdateDomain\":\"0\",\"provider\":\"Microsoft.Compute\",\"publicKeys\":[{\"keyData\":\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5uCeOAm3ehmhI+2PbMoMl17Eo\r\nqfHKCycSaBJsv9qxlmBOuFheSJc1XknJleXUSsuTO016/d1PyWpevnqOZNRksWoa\r\nJvQ23sDTxcK+X2OP3QlCUeX4cMjPXqlL8z1UYzU4Bx3fFvf8fs67G3N72sxWBw5P\r\nZyuXyhBm0NCe/2NYMKgEDT4ma8XszO0ikbhoPKbMbgHAQk/ktWQHNcqYOPQKEWqp\r\nEK1R0rjS2nmtovfScP/ZGXcvOpJ1/NDBo4dh1K+OxOGM/4PSH/F448J5Zy4eAyEk\r\nscys+IpeIOTOlRUy/703SNIX0LEWlnYqbyL9c1ypcYLQqF76fKkDfzzFI/OWVlGw\r\nhj/S9uP8iMsR+fhGIbn6MAa7O4DWPWLuedSp7KDYyjY09gqNJsfuaAJN4LiC6bPy\r\nhknm0PVLK3ux7EUOt+cZrHCdIFWbdOtxiPNIl1tkv9kV5aE5Aj2gJm4MeB9uXYhS\r\nOuksboBc0wyUGrl9+XZJ1+NlZOf7IjVi86CieK8= generated-by-azure\r\n\",\"path\":\"/home/azureuser/.ssh/authorized_keys\"}],\"publisher\":\"Canonical\",\"resourceGroupName\":\"sourabh-telemetry-sdk\",\"resourceId\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/virtualMachines/sourabh-testing\",\"securityProfile\":{\"secureBootEnabled\":\"false\",\"virtualTpmEnabled\":\"false\"},\"sku\":\"18.04-LTS\",\"storageProfile\":{\"dataDisks\":[],\"imageReference\":{\"id\":\"\",\"offer\":\"UbuntuServer\",\"publisher\":\"Canonical\",\"sku\":\"18.04-LTS\",\"version\":\"latest\"},\"osDisk\":{\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\",\"diffDiskSettings\":{\"option\":\"\"},\"diskSizeGB\":\"30\",\"encryptionSettings\":{\"enabled\":\"false\"},\"image\":{\"uri\":\"\"},\"managedDisk\":{\"id\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/disks/sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"storageAccountType\":\"Premium_LRS\"},\"name\":\"sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"osType\":\"Linux\",\"vhd\":{\"uri\":\"\"},\"writeAcceleratorEnabled\":\"false\"}},\"subscriptionId\":\"8fba6d4f-7c37-4d13-9063-fd58ad2b86e2\",\"tags\":\"azsecpack:nonprod;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true\",\"tagsList\":[{\"name\":\"azsecpack\",\"value\":\"nonprod\"},{\"name\":\"platformsettings.host_environment.service.platform_optedin_for_rootcerts\",\"value\":\"true\"}],\"version\":\"18.04.202103250\",\"vmId\":\"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd\",\"vmScaleSetName\":\"\",\"vmSize\":\"Standard_D2s_v3\",\"zone\":\"1\"},\"network\":{\"interface\":[{\"ipv4\":{\"ipAddress\":[{\"privateIpAddress\":\"10.0.7.5\",\"publicIpAddress\":\"\"}],\"subnet\":[{\"address\":\"10.0.7.0\",\"prefix\":\"24\"}]},\"ipv6\":{\"ipAddress\":[]},\"macAddress\":\"000D3A8F8BA0\"}]}}"); - string payload = JsonConvert.SerializeObject(jsonObject); - result.Content = new StringContent(payload, Encoding.UTF8, "application/json"); - - AzureVMMetadata metadata = await VmMetadataApiHandler.ProcessResponseAsync(result); - - Assert.AreEqual("eastus", metadata.Compute.Location); - Assert.AreEqual("18.04-LTS", metadata.Compute.SKU); - Assert.AreEqual("AzurePublicCloud", metadata.Compute.AzEnvironment); - Assert.AreEqual("Linux", metadata.Compute.OSType); - Assert.AreEqual("Standard_D2s_v3", metadata.Compute.VMSize); - Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", metadata.Compute.VMId); - } - [TestMethod] public void CheckMetricsAggregationLogic() { @@ -131,6 +111,5 @@ public void CheckMisconfiguredTelemetry_should_fail() Environment.SetEnvironmentVariable(ClientTelemetryOptions.EnvPropsClientTelemetryEnabled, "non-boolean"); using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); } - } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs index 88e27d0638..997c9b4c9c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs @@ -73,6 +73,36 @@ public async Task GetHashedMachineNameAsMachineIdTest() Assert.AreEqual(expectedMachineId, VmMetadataApiHandler.GetMachineId()); } + + [TestMethod] + public void ComputeHashTest() + { + string hashedValue = VmMetadataApiHandler.ComputeHash("abc"); + Assert.AreEqual("bf1678ba-018f-eacf-4141-40de5dae2223", hashedValue); + } + + + [TestMethod] + public async Task ParseAzureVMMetadataTest() + { + HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); + + // Add a substatus code that is not part of the enum. + // This ensures that if the backend adds a enum the status code is not lost. + object jsonObject = JsonConvert.DeserializeObject("{\"compute\":{\"azEnvironment\":\"AzurePublicCloud\",\"customData\":\"\",\"isHostCompatibilityLayerVm\":\"false\",\"licenseType\":\"\",\"location\":\"eastus\",\"name\":\"sourabh-testing\",\"offer\":\"UbuntuServer\",\"osProfile\":{\"adminUsername\":\"azureuser\",\"computerName\":\"sourabh-testing\"},\"osType\":\"Linux\",\"placementGroupId\":\"\",\"plan\":{\"name\":\"\",\"product\":\"\",\"publisher\":\"\"},\"platformFaultDomain\":\"0\",\"platformUpdateDomain\":\"0\",\"provider\":\"Microsoft.Compute\",\"publicKeys\":[{\"keyData\":\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5uCeOAm3ehmhI+2PbMoMl17Eo\r\nqfHKCycSaBJsv9qxlmBOuFheSJc1XknJleXUSsuTO016/d1PyWpevnqOZNRksWoa\r\nJvQ23sDTxcK+X2OP3QlCUeX4cMjPXqlL8z1UYzU4Bx3fFvf8fs67G3N72sxWBw5P\r\nZyuXyhBm0NCe/2NYMKgEDT4ma8XszO0ikbhoPKbMbgHAQk/ktWQHNcqYOPQKEWqp\r\nEK1R0rjS2nmtovfScP/ZGXcvOpJ1/NDBo4dh1K+OxOGM/4PSH/F448J5Zy4eAyEk\r\nscys+IpeIOTOlRUy/703SNIX0LEWlnYqbyL9c1ypcYLQqF76fKkDfzzFI/OWVlGw\r\nhj/S9uP8iMsR+fhGIbn6MAa7O4DWPWLuedSp7KDYyjY09gqNJsfuaAJN4LiC6bPy\r\nhknm0PVLK3ux7EUOt+cZrHCdIFWbdOtxiPNIl1tkv9kV5aE5Aj2gJm4MeB9uXYhS\r\nOuksboBc0wyUGrl9+XZJ1+NlZOf7IjVi86CieK8= generated-by-azure\r\n\",\"path\":\"/home/azureuser/.ssh/authorized_keys\"}],\"publisher\":\"Canonical\",\"resourceGroupName\":\"sourabh-telemetry-sdk\",\"resourceId\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/virtualMachines/sourabh-testing\",\"securityProfile\":{\"secureBootEnabled\":\"false\",\"virtualTpmEnabled\":\"false\"},\"sku\":\"18.04-LTS\",\"storageProfile\":{\"dataDisks\":[],\"imageReference\":{\"id\":\"\",\"offer\":\"UbuntuServer\",\"publisher\":\"Canonical\",\"sku\":\"18.04-LTS\",\"version\":\"latest\"},\"osDisk\":{\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\",\"diffDiskSettings\":{\"option\":\"\"},\"diskSizeGB\":\"30\",\"encryptionSettings\":{\"enabled\":\"false\"},\"image\":{\"uri\":\"\"},\"managedDisk\":{\"id\":\"/subscriptions/8fba6d4f-7c37-4d13-9063-fd58ad2b86e2/resourceGroups/sourabh-telemetry-sdk/providers/Microsoft.Compute/disks/sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"storageAccountType\":\"Premium_LRS\"},\"name\":\"sourabh-testing_OsDisk_1_9a54abfc5ba149c6a106bd9e5b558c2a\",\"osType\":\"Linux\",\"vhd\":{\"uri\":\"\"},\"writeAcceleratorEnabled\":\"false\"}},\"subscriptionId\":\"8fba6d4f-7c37-4d13-9063-fd58ad2b86e2\",\"tags\":\"azsecpack:nonprod;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true\",\"tagsList\":[{\"name\":\"azsecpack\",\"value\":\"nonprod\"},{\"name\":\"platformsettings.host_environment.service.platform_optedin_for_rootcerts\",\"value\":\"true\"}],\"version\":\"18.04.202103250\",\"vmId\":\"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd\",\"vmScaleSetName\":\"\",\"vmSize\":\"Standard_D2s_v3\",\"zone\":\"1\"},\"network\":{\"interface\":[{\"ipv4\":{\"ipAddress\":[{\"privateIpAddress\":\"10.0.7.5\",\"publicIpAddress\":\"\"}],\"subnet\":[{\"address\":\"10.0.7.0\",\"prefix\":\"24\"}]},\"ipv6\":{\"ipAddress\":[]},\"macAddress\":\"000D3A8F8BA0\"}]}}"); + string payload = JsonConvert.SerializeObject(jsonObject); + result.Content = new StringContent(payload, Encoding.UTF8, "application/json"); + + AzureVMMetadata metadata = await VmMetadataApiHandler.ProcessResponseAsync(result); + + Assert.AreEqual("eastus", metadata.Compute.Location); + Assert.AreEqual("18.04-LTS", metadata.Compute.SKU); + Assert.AreEqual("AzurePublicCloud", metadata.Compute.AzEnvironment); + Assert.AreEqual("Linux", metadata.Compute.OSType); + Assert.AreEqual("Standard_D2s_v3", metadata.Compute.VMSize); + Assert.AreEqual("vmId:d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd", metadata.Compute.VMId); + } + private class MockMessageHandler : HttpMessageHandler { private readonly Func> sendFunc;