Skip to content

Commit 6d36c36

Browse files
authored
VM Metadata API: Adds an option to disable VM metadata API call (#4568)
* add env variable * fixed tests * removed try-catch * add doc * remove else * put try-catch around test * remove debugger * update env variable name and updated known issue section * updstade doc
1 parent 5287ffb commit 6d36c36

File tree

3 files changed

+65
-25
lines changed

3 files changed

+65
-25
lines changed

Microsoft.Azure.Cosmos/src/Telemetry/VmMetadataApiHandler.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,23 @@ internal static class VmMetadataApiHandler
3434

3535
private static bool isInitialized = false;
3636
private static AzureVMMetadata azMetadata = null;
37-
37+
38+
/// <summary>
39+
/// Check for environment variable COSMOS_DISABLE_IMDS_ACCESS to decide if VM metadata call should be made or not.
40+
/// If environment variable is set to true, then VM metadata call will not be made.
41+
/// If environment variable is set to false, then VM metadata call will be made.
42+
/// If environment variable is not set, then VM metadata call will be made.
43+
/// </summary>.
44+
/// <param name="httpClient"></param>
3845
internal static void TryInitialize(CosmosHttpClient httpClient)
3946
{
47+
bool isVMMetadataAccessDisabled =
48+
ConfigurationManager.GetEnvironmentVariable<bool>("COSMOS_DISABLE_IMDS_ACCESS", false);
49+
if (isVMMetadataAccessDisabled)
50+
{
51+
return;
52+
}
53+
4054
if (VmMetadataApiHandler.isInitialized)
4155
{
4256
return;
@@ -55,7 +69,6 @@ internal static void TryInitialize(CosmosHttpClient httpClient)
5569

5670
_ = Task.Run(() => MetadataApiCallAsync(httpClient), default);
5771
}
58-
5972
}
6073

6174
private static async Task MetadataApiCallAsync(CosmosHttpClient httpClient)

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/VmMetadataApiHandlerTest.cs

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ namespace Microsoft.Azure.Cosmos
1717
using Microsoft.Azure.Cosmos.Telemetry.Models;
1818
using Microsoft.Azure.Cosmos.Tests;
1919
using Microsoft.VisualStudio.TestTools.UnitTesting;
20-
using Moq;
2120
using Newtonsoft.Json;
2221
using Util;
2322

2423
[TestClass]
2524
public class VmMetadataApiHandlerTest
2625
{
2726
[TestInitialize]
28-
public void Intialize()
27+
public void Initialize()
2928
{
3029
var isInitializedField = typeof(VmMetadataApiHandler).GetField("isInitialized",
3130
BindingFlags.Static |
@@ -39,27 +38,54 @@ public void Intialize()
3938
}
4039

4140
[TestMethod]
42-
public async Task GetVmIdAsMachineIdTest()
41+
[DataRow("true", DisplayName = "When COSMOS_DISABLE_IMDS_ACCESS is set as true, VM ID should not be fetched")]
42+
[DataRow("false", DisplayName = "When COSMOS_DISABLE_IMDS_ACCESS is set as false, VM ID should be fetched")]
43+
[DataRow(null, DisplayName = "When COSMOS_DISABLE_IMDS_ACCESS is NOT set, VM ID should be fetched")]
44+
public async Task GetVmIdAsMachineIdTest(string isVmMetadataAccessDisabled)
4345
{
44-
static Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, CancellationToken cancellationToken)
46+
if (isVmMetadataAccessDisabled != null)
4547
{
46-
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\"}]}}");
47-
string payload = JsonConvert.SerializeObject(jsonObject);
48-
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
48+
Environment.SetEnvironmentVariable("COSMOS_DISABLE_IMDS_ACCESS", isVmMetadataAccessDisabled);
49+
}
50+
51+
try
52+
{
53+
static Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, CancellationToken cancellationToken)
4954
{
50-
Content = new StringContent(payload, Encoding.UTF8, "application/json")
51-
};
52-
return Task.FromResult(response);
53-
}
55+
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\"}]}}");
56+
string payload = JsonConvert.SerializeObject(jsonObject);
57+
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
58+
{
59+
Content = new StringContent(payload, Encoding.UTF8, "application/json")
60+
};
61+
return Task.FromResult(response);
62+
}
5463

55-
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
56-
CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
64+
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
65+
CosmosHttpClient cosmosHttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
5766

58-
VmMetadataApiHandler.TryInitialize(cosmoshttpClient);
67+
VmMetadataApiHandler.TryInitialize(cosmosHttpClient);
5968

60-
await Task.Delay(2000);
61-
Assert.AreEqual($"{VmMetadataApiHandler.VmIdPrefix}{"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd"}", VmMetadataApiHandler.GetMachineId());
62-
Assert.AreEqual(VmMetadataApiHandler.GetMachineRegion(), "eastus");
69+
await Task.Delay(2000);
70+
71+
if (isVmMetadataAccessDisabled != null &&
72+
Boolean.TryParse(isVmMetadataAccessDisabled, out bool isVmMetadataAccessDisabledBool) &&
73+
isVmMetadataAccessDisabledBool)
74+
{
75+
Assert.AreNotEqual($"{VmMetadataApiHandler.VmIdPrefix}{"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd"}", VmMetadataApiHandler.GetMachineId());
76+
Assert.IsNull(VmMetadataApiHandler.GetMachineRegion(), VmMetadataApiHandler.GetMachineRegion());
77+
}
78+
else
79+
{
80+
Assert.AreEqual($"{VmMetadataApiHandler.VmIdPrefix}{"d0cb93eb-214b-4c2b-bd3d-cc93e90d9efd"}", VmMetadataApiHandler.GetMachineId());
81+
Assert.AreEqual(VmMetadataApiHandler.GetMachineRegion(), "eastus");
82+
}
83+
84+
}
85+
finally
86+
{
87+
Environment.SetEnvironmentVariable("COSMOS_DISABLE_IMDS_ACCESS", null);
88+
}
6389
}
6490

6591
[TestMethod]
@@ -77,9 +103,9 @@ static Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, Cancellati
77103
}
78104

79105
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
80-
CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
106+
CosmosHttpClient cosmosHttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
81107

82-
VmMetadataApiHandler.TryInitialize(cosmoshttpClient);
108+
VmMetadataApiHandler.TryInitialize(cosmosHttpClient);
83109

84110
await Task.Delay(2000);
85111
Assert.IsNull(VmMetadataApiHandler.GetMachineInfo());
@@ -95,9 +121,9 @@ public async Task GetHashedMachineNameAsMachineIdTest()
95121
static Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) { throw new Exception("error while making API call"); };
96122

97123
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
98-
CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
124+
CosmosHttpClient cosmosHttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
99125

100-
VmMetadataApiHandler.TryInitialize(cosmoshttpClient);
126+
VmMetadataApiHandler.TryInitialize(cosmosHttpClient);
101127

102128
await Task.Delay(2000);
103129
Assert.AreEqual(expectedMachineId, VmMetadataApiHandler.GetMachineId());
@@ -139,7 +165,7 @@ public void CatchMetadataApiCallExceptionTest()
139165
static Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) { throw new Exception("error while making API call"); };
140166

141167
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
142-
CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
168+
CosmosHttpClient cosmosHttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));
143169

144170
string expectedMsg = "Azure Environment metadata information not available.";
145171
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
@@ -155,7 +181,7 @@ void TraceHandler(string message)
155181
DefaultTrace.TraceSource.Listeners.Add(new TestTraceListener { Callback = TraceHandler });
156182
DefaultTrace.InitEventListener();
157183

158-
VmMetadataApiHandler.TryInitialize(cosmoshttpClient);
184+
VmMetadataApiHandler.TryInitialize(cosmosHttpClient);
159185

160186
int timeout = 30000;
161187
Assert.IsTrue(manualResetEvent.WaitOne(timeout));

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,7 @@ Below is a list of any know issues affecting the [recommended minimum version](#
13931393
| --- | --- | --- | --- |
13941394
| `FeedIterator` enters an infinite loop after a physical partition split occurs in a container using hierarchical partition keys. | Queries using prefix partition keys. | Rather than having the PK included in the query request options, filtering on top level hierarchical Pks should be done through where clauses. | [#4326](https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4326) |
13951395
| Single partition queries (queries explicitly targetted to single partition or any queries on collection that had single physical partition) that resume using continuation token after partition split can observe failure on SDK v3.38 and beyond. | Explicit query exeuction using continuation token will fail query execution if these conditions are met. | Turn off Optimistic Direct Execution during query execution either by setting EnableOptimisticDirectExecution to false in query request options or by setting environment variable AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED to false. | [#4432](https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4432) |
1396+
| An [Azure API](https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux) call is made to get the VM information. This call fails if cutomer is on non-Azure VM. | Although this call is made only once, during client initialization but this failure would come up into monitoring tool (e.g AppInsights, Datadog etc.) which leads to a confusion for a developer.| Turn off this call by setting environment variable COSMOS_DISABLE_IMDS_ACCESS to true. |[#4187](https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4187) |
13961397

13971398
## Release & Retirement dates
13981399

0 commit comments

Comments
 (0)