diff --git a/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md b/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md index 0478c1627ce4..54e2fe7d30d0 100644 --- a/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md +++ b/sdk/monitor/Azure.Monitor.Query/CHANGELOG.md @@ -7,6 +7,7 @@ ### Breaking Changes ### Bugs Fixed +- Enable national cloud support for US Gov and China clouds ### Other Changes diff --git a/sdk/monitor/Azure.Monitor.Query/README.md b/sdk/monitor/Azure.Monitor.Query/README.md index 51327e259dcb..4e4d2db39d0d 100644 --- a/sdk/monitor/Azure.Monitor.Query/README.md +++ b/sdk/monitor/Azure.Monitor.Query/README.md @@ -470,7 +470,7 @@ var client = new MetricsQueryClient(new DefaultAzureCredential()); Response results = await client.QueryResourceAsync( resourceId, - new[] { "AvailabilityRate_Query", "Query Count" } + new[] { "Average_% Free Space", "Average_% Used Space" } ); foreach (MetricResult metric in results.Value.Metrics) @@ -522,8 +522,7 @@ string resourceId = "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/TestVault"; string[] metricNames = new[] { "Availability" }; var client = new MetricsQueryClient(new DefaultAzureCredential()); - -Response result = await client.QueryResourceAsync( +Response result = await client.QueryResourceAsync( resourceId, metricNames, new MetricsQueryOptions @@ -555,6 +554,7 @@ To programmatically retrieve metrics namespaces, use the following code: string resourceId = "/subscriptions//resourceGroups//providers/Microsoft.Web/sites/TestWebApp"; var client = new MetricsQueryClient(new DefaultAzureCredential()); + AsyncPageable metricNamespaces = client.GetMetricNamespacesAsync(resourceId); await foreach (var metricNamespace in metricNamespaces) @@ -574,6 +574,7 @@ string[] metricNames = new[] { "Http2xx" }; // Use of asterisk in filter value enables splitting on Instance dimension. string filter = "Instance eq '*'"; var client = new MetricsQueryClient(new DefaultAzureCredential()); + var options = new MetricsQueryOptions { Aggregations = @@ -603,6 +604,8 @@ foreach (MetricResult metric in result.Value.Metrics) } ``` +For an inventory of metrics and dimensions available for each Azure resource type, see [Supported metrics with Azure Monitor](https://learn.microsoft.com/azure/azure-monitor/essentials/metrics-supported). + #### Register the client with dependency injection To register `LogsQueryClient` with the dependency injection (DI) container, invoke the `AddLogsQueryClient` method. To register `MetricsQueryClient` with the dependency injection (DI) container, invoke the `AddMetricsQueryClient` method. For more information, see [Register client](https://learn.microsoft.com/dotnet/azure/sdk/dependency-injection#register-client). diff --git a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs index 1f2bb9127d9d..5982c8d435a2 100644 --- a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs +++ b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs @@ -5,6 +5,25 @@ public partial class LogsBatchQuery public LogsBatchQuery() { } public virtual string AddWorkspaceQuery(string workspaceId, string query, Azure.Monitor.Query.QueryTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null) { throw null; } } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct LogsQueryAudience : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public LogsQueryAudience(string value) { throw null; } + public static Azure.Monitor.Query.LogsQueryAudience AzureChina { get { throw null; } } + public static Azure.Monitor.Query.LogsQueryAudience AzureGovernment { get { throw null; } } + public static Azure.Monitor.Query.LogsQueryAudience AzurePublicCloud { get { throw null; } } + public bool Equals(Azure.Monitor.Query.LogsQueryAudience other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Monitor.Query.LogsQueryAudience left, Azure.Monitor.Query.LogsQueryAudience right) { throw null; } + public static implicit operator Azure.Monitor.Query.LogsQueryAudience (string value) { throw null; } + public static bool operator !=(Azure.Monitor.Query.LogsQueryAudience left, Azure.Monitor.Query.LogsQueryAudience right) { throw null; } + public override string ToString() { throw null; } + } public partial class LogsQueryClient { protected LogsQueryClient() { } @@ -28,6 +47,7 @@ public LogsQueryClient(System.Uri endpoint, Azure.Core.TokenCredential credentia public partial class LogsQueryClientOptions : Azure.Core.ClientOptions { public LogsQueryClientOptions(Azure.Monitor.Query.LogsQueryClientOptions.ServiceVersion version = Azure.Monitor.Query.LogsQueryClientOptions.ServiceVersion.V1) { } + public Azure.Monitor.Query.LogsQueryAudience? Audience { get { throw null; } set { } } public enum ServiceVersion { V1 = 1, @@ -42,6 +62,41 @@ public LogsQueryOptions() { } public bool IncludeVisualization { get { throw null; } set { } } public System.TimeSpan? ServerTimeout { get { throw null; } set { } } } + public partial class MetricsBatchQueryClient + { + protected MetricsBatchQueryClient() { } + public MetricsBatchQueryClient(System.Uri endpoint, Azure.Core.TokenCredential credential, Azure.Monitor.Query.MetricsBatchQueryClientOptions options = null) { } + public System.Uri Endpoint { get { throw null; } } + public virtual Azure.Response QueryBatch(System.Collections.Generic.List resourceIds, System.Collections.Generic.List metricNames, string metricNamespace, Azure.Monitor.Query.MetricsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> QueryBatchAsync(System.Collections.Generic.List resourceIds, System.Collections.Generic.List metricNames, string metricNamespace, Azure.Monitor.Query.MetricsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } + public partial class MetricsBatchQueryClientOptions : Azure.Core.ClientOptions + { + public MetricsBatchQueryClientOptions(Azure.Monitor.Query.MetricsBatchQueryClientOptions.ServiceVersion version = Azure.Monitor.Query.MetricsBatchQueryClientOptions.ServiceVersion.V2023_05_01_PREVIEW) { } + public enum ServiceVersion + { + V2023_05_01_PREVIEW = 1, + } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct MetricsQueryAudience : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public MetricsQueryAudience(string value) { throw null; } + public static Azure.Monitor.Query.MetricsQueryAudience AzureChina { get { throw null; } } + public static Azure.Monitor.Query.MetricsQueryAudience AzureGovernment { get { throw null; } } + public static Azure.Monitor.Query.MetricsQueryAudience AzurePublicCloud { get { throw null; } } + public bool Equals(Azure.Monitor.Query.MetricsQueryAudience other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Monitor.Query.MetricsQueryAudience left, Azure.Monitor.Query.MetricsQueryAudience right) { throw null; } + public static implicit operator Azure.Monitor.Query.MetricsQueryAudience (string value) { throw null; } + public static bool operator !=(Azure.Monitor.Query.MetricsQueryAudience left, Azure.Monitor.Query.MetricsQueryAudience right) { throw null; } + public override string ToString() { throw null; } + } public partial class MetricsQueryClient { protected MetricsQueryClient() { } @@ -59,6 +114,7 @@ public MetricsQueryClient(System.Uri endpoint, Azure.Core.TokenCredential creden public partial class MetricsQueryClientOptions : Azure.Core.ClientOptions { public MetricsQueryClientOptions(Azure.Monitor.Query.MetricsQueryClientOptions.ServiceVersion version = Azure.Monitor.Query.MetricsQueryClientOptions.ServiceVersion.V2018_01_01) { } + public Azure.Monitor.Query.MetricsQueryAudience? Audience { get { throw null; } set { } } public enum ServiceVersion { V2018_01_01 = 1, diff --git a/sdk/monitor/Azure.Monitor.Query/assets.json b/sdk/monitor/Azure.Monitor.Query/assets.json index d849d48b9acf..afda7d7ab54b 100644 --- a/sdk/monitor/Azure.Monitor.Query/assets.json +++ b/sdk/monitor/Azure.Monitor.Query/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/monitor/Azure.Monitor.Query", - "Tag": "net/monitor/Azure.Monitor.Query_c676889fde" + "Tag": "net/monitor/Azure.Monitor.Query_ae071e9780" } diff --git a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs index 58ba047fa7de..faef24004a03 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs @@ -39,11 +39,11 @@ public LogsQueryClient(TokenCredential credential) : this(credential, null) } /// - /// Initializes a new instance of . Uses the default 'https://api.loganalytics.io' endpoint. + /// Initializes a new instance of . Uses the default 'https://api.loganalytics.io' endpoint if Audience is not set in LogsQueryClientOptions. /// /// The instance to use for authentication. /// The instance to use as client configuration. - public LogsQueryClient(TokenCredential credential, LogsQueryClientOptions options) : this(_defaultEndpoint, credential, options) + public LogsQueryClient(TokenCredential credential, LogsQueryClientOptions options) : this(string.IsNullOrEmpty(options.Audience?.ToString()) ? _defaultEndpoint : new Uri(options.Audience.ToString()), credential, options) { } @@ -69,11 +69,13 @@ public LogsQueryClient(Uri endpoint, TokenCredential credential, LogsQueryClient Endpoint = endpoint; options ??= new LogsQueryClientOptions(); - var scope = $"{endpoint.AbsoluteUri}/.default"; + var authorizationScope = $"{(string.IsNullOrEmpty(options.Audience?.ToString()) ? LogsQueryAudience.AzurePublicCloud : options.Audience)}"; + authorizationScope += "//.default"; + var scopes = new List { authorizationScope }; endpoint = new Uri(endpoint, options.GetVersionString()); _clientDiagnostics = new ClientDiagnostics(options); - _pipeline = HttpPipelineBuilder.Build(options, new BearerTokenAuthenticationPolicy(credential, scope)); + _pipeline = HttpPipelineBuilder.Build(options, new BearerTokenAuthenticationPolicy(credential, scopes)); _queryClient = new QueryRestClient(_clientDiagnostics, _pipeline, endpoint); } diff --git a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClientOptions.cs b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClientOptions.cs index 4b84ef1b6876..c7f048090d48 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClientOptions.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClientOptions.cs @@ -52,5 +52,11 @@ internal string GetVersionString() _ => throw new ArgumentException(@"Unknown version {_version}") }; } + + /// + /// Gets or sets the audience to use for authentication with Microsoft Entra ID. The audience is not considered when using a shared key. + /// + /// If null, will be assumed. + public LogsQueryAudience? Audience { get; set; } } } diff --git a/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClient.cs b/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClient.cs index d2c812ba0211..a2142a97a617 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClient.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClient.cs @@ -14,7 +14,7 @@ namespace Azure.Monitor.Query /// /// The allows you to query multiple Azure Monitor Metric services. /// - internal class MetricsBatchQueryClient + public class MetricsBatchQueryClient { private readonly MetricsBatchRestClient _metricBatchClient; private readonly ClientDiagnostics _clientDiagnostics; diff --git a/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClientOptions.cs b/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClientOptions.cs index 9cba1276ccb8..b6b2f8bc5c33 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClientOptions.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/MetricsBatchQueryClientOptions.cs @@ -8,7 +8,7 @@ namespace Azure.Monitor.Query /// /// Provides the client configuration options for connecting to Azure Monitor Metrics service. /// - internal class MetricsBatchQueryClientOptions: ClientOptions + public class MetricsBatchQueryClientOptions: ClientOptions { private readonly ServiceVersion _version; diff --git a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs index 0d30ddbe8637..bbab0b73bf2d 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs @@ -35,11 +35,11 @@ public MetricsQueryClient(TokenCredential credential) : this(credential, null) } /// - /// Initializes a new instance of . Uses the default 'https://management.azure.com' endpoint. + /// Initializes a new instance of . Uses the default 'https://management.azure.com' endpoint if Audience is not set in MetricsQueryClientOptions. /// /// The instance to use for authentication. /// The instance to as client configuration. - public MetricsQueryClient(TokenCredential credential, MetricsQueryClientOptions options) : this(_defaultEndpoint, credential, options) + public MetricsQueryClient(TokenCredential credential, MetricsQueryClientOptions options) : this(string.IsNullOrEmpty(options.Audience?.ToString()) ? _defaultEndpoint : new Uri(options.Audience.ToString()), credential, options) { } @@ -54,15 +54,16 @@ public MetricsQueryClient(Uri endpoint, TokenCredential credential, MetricsQuery Argument.AssertNotNull(credential, nameof(credential)); options ??= new MetricsQueryClientOptions(); + var authorizationScope = $"{(string.IsNullOrEmpty(options.Audience?.ToString()) ? MetricsQueryAudience.AzurePublicCloud : options.Audience)}"; + authorizationScope += "//.default"; + var scopes = new List { authorizationScope }; _clientDiagnostics = new ClientDiagnostics(options); - var scope = $"{endpoint.AbsoluteUri}/.default"; - Endpoint = endpoint; var pipeline = HttpPipelineBuilder.Build(options, - new BearerTokenAuthenticationPolicy(credential, scope)); + new BearerTokenAuthenticationPolicy(credential, scopes)); _metricDefinitionsClient = new MetricDefinitionsRestClient(_clientDiagnostics, pipeline, endpoint); _metricsRestClient = new MetricsRestClient(_clientDiagnostics, pipeline, endpoint); @@ -90,7 +91,7 @@ protected MetricsQueryClient() /// /// Response<MetricsQueryResult> results = await client.QueryResourceAsync( /// resourceId, - /// new[] { "AvailabilityRate_Query", "Query Count" } + /// new[] { "Average_% Free Space", "Average_% Used Space" } /// ); /// /// foreach (MetricResult metric in results.Value.Metrics) @@ -151,7 +152,7 @@ public virtual Response QueryResource(string resourceId, IEn /// /// Response<MetricsQueryResult> results = await client.QueryResourceAsync( /// resourceId, - /// new[] { "AvailabilityRate_Query", "Query Count" } + /// new[] { "Average_% Free Space", "Average_% Used Space" } /// ); /// /// foreach (MetricResult metric in results.Value.Metrics) diff --git a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClientOptions.cs b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClientOptions.cs index c3ee62d8483d..22292b9bd504 100644 --- a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClientOptions.cs +++ b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClientOptions.cs @@ -42,5 +42,11 @@ public enum ServiceVersion V2018_01_01 = 1, #pragma warning restore CA1707 // Identifiers should not contain underscores } + + /// + /// Gets or sets the audience to use for authentication with Microsoft Entra ID. The audience is not considered when using a shared key. + /// + /// If null, will be assumed. + public MetricsQueryAudience? Audience { get; set; } } } diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryAudience.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryAudience.cs new file mode 100644 index 000000000000..e7515f5db86b --- /dev/null +++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryAudience.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using Azure.Core; + +namespace Azure.Monitor.Query +{ + /// Cloud audiences available for Query. + public readonly partial struct LogsQueryAudience : IEquatable + { + private readonly string _value; + + /// + /// Initializes a new instance of the object. + /// + /// The Microsoft Entra audience to use when forming authorization scopes. For the language service, this value corresponds to a URL that identifies the Azure cloud where the resource is located. For more information: . + /// is null. + /// Use one of the constant members over creating a custom value, unless you have special needs for doing so. + public LogsQueryAudience(string value) + { + Argument.AssertNotNullOrEmpty(value, nameof(value)); + _value = value; + } + + private const string AzureChinaValue = "https://api.loganalytics.azure.cn"; + private const string AzureGovernmentValue = "https://api.loganalytics.us"; + private const string AzurePublicCloudValue = "https://api.loganalytics.io"; + + /// Azure China. + public static LogsQueryAudience AzureChina { get; } = new LogsQueryAudience(AzureChinaValue); + + /// Azure US Government. + public static LogsQueryAudience AzureGovernment { get; } = new LogsQueryAudience(AzureGovernmentValue); + + /// Azure Public Cloud. + public static LogsQueryAudience AzurePublicCloud { get; } = new LogsQueryAudience(AzurePublicCloudValue); + + /// Determines if two values are the same. + public static bool operator ==(LogsQueryAudience left, LogsQueryAudience right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(LogsQueryAudience left, LogsQueryAudience right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator LogsQueryAudience(string value) => new LogsQueryAudience(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is LogsQueryAudience other && Equals(other); + /// + public bool Equals(LogsQueryAudience other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/MetricsQueryAudience.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/MetricsQueryAudience.cs new file mode 100644 index 000000000000..8f5befea3d93 --- /dev/null +++ b/sdk/monitor/Azure.Monitor.Query/src/Models/MetricsQueryAudience.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using Azure.Core; + +namespace Azure.Monitor.Query +{ + /// Cloud audiences available for Query. + public readonly partial struct MetricsQueryAudience : IEquatable + { + private readonly string _value; + + /// + /// Initializes a new instance of the object. + /// + /// The Microsoft Entra audience to use when forming authorization scopes. For the language service, this value corresponds to a URL that identifies the Azure cloud where the resource is located. For more information: . + /// is null. + /// Use one of the constant members over creating a custom value, unless you have special needs for doing so. + public MetricsQueryAudience(string value) + { + Argument.AssertNotNullOrEmpty(value, nameof(value)); + _value = value; + } + + private const string AzureChinaValue = "https://management.chinacloudapi.cn"; + private const string AzureGovernmentValue = "https://management.usgovcloudapi.net"; + private const string AzurePublicCloudValue = "https://management.azure.com"; + + /// Azure China. + public static MetricsQueryAudience AzureChina { get; } = new MetricsQueryAudience(AzureChinaValue); + + /// Azure US Government. + public static MetricsQueryAudience AzureGovernment { get; } = new MetricsQueryAudience(AzureGovernmentValue); + + /// Azure Public Cloud. + public static MetricsQueryAudience AzurePublicCloud { get; } = new MetricsQueryAudience(AzurePublicCloudValue); + + /// Determines if two values are the same. + public static bool operator ==(MetricsQueryAudience left, MetricsQueryAudience right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(MetricsQueryAudience left, MetricsQueryAudience right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator MetricsQueryAudience(string value) => new MetricsQueryAudience(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is MetricsQueryAudience other && Equals(other); + /// + public bool Equals(MetricsQueryAudience other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/monitor/Azure.Monitor.Query/tests.yml b/sdk/monitor/Azure.Monitor.Query/tests.yml index 2498ec29ae4f..21bb2f5114e1 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests.yml +++ b/sdk/monitor/Azure.Monitor.Query/tests.yml @@ -4,5 +4,6 @@ extends: template: /eng/pipelines/templates/stages/archetype-sdk-tests.yml parameters: ServiceDirectory: monitor + SupportedClouds: 'Public,UsGov,China' Project: Azure.Monitor.Query TimeoutInMinutes: 120 diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientLiveTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientLiveTests.cs index c7ffa31b1d52..8d4ee53fae1c 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientLiveTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientLiveTests.cs @@ -32,11 +32,12 @@ public void SetUp() private LogsQueryClient CreateClient() { return InstrumentClient(new LogsQueryClient( - TestEnvironment.LogsEndpoint, + new Uri(TestEnvironment.GetLogsAudience() + "/v1"), TestEnvironment.Credential, InstrumentClientOptions(new LogsQueryClientOptions() { - Diagnostics = { IsLoggingContentEnabled = true } + Diagnostics = { IsLoggingContentEnabled = true }, + Audience = TestEnvironment.GetLogsAudience() }) )); } diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs index f06ffe0cb880..55c438e6ee11 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientTests.cs @@ -141,10 +141,21 @@ public async Task UsesDefaultEndpoint() StringAssert.StartsWith("https://api.loganalytics.io", mockTransport.SingleRequest.Uri.ToString()); } - [TestCase(null, "https://api.loganalytics.io//.default")] - [TestCase("https://api.loganalytics.gov", "https://api.loganalytics.gov//.default")] - [TestCase("https://api.loganalytics.cn", "https://api.loganalytics.cn//.default")] - public async Task UsesDefaultAuthScope(string host, string expectedScope) + /// + /// Provides the invalid test cases for the constructor tests. + /// + /// + private static IEnumerable GetAudience() + { + yield return new object[] { null, "https://api.loganalytics.io//.default" }; + yield return new object[] { LogsQueryAudience.AzurePublicCloud, "https://api.loganalytics.io//.default" }; + yield return new object[] { LogsQueryAudience.AzureGovernment, "https://api.loganalytics.us//.default" }; + yield return new object[] { LogsQueryAudience.AzureChina, "https://api.loganalytics.azure.cn//.default" }; + } + + [Test] + [TestCaseSource(nameof(GetAudience))] + public async Task UsesDefaultAuthScope(LogsQueryAudience audience, string expectedScope) { var mockTransport = MockTransport.FromMessageCallback(message => { @@ -162,12 +173,11 @@ public async Task UsesDefaultAuthScope(string host, string expectedScope) var options = new LogsQueryClientOptions() { - Transport = mockTransport + Transport = mockTransport, + Audience = audience }; - var client = host == null ? - new LogsQueryClient(mock.Object, options) : - new LogsQueryClient(new Uri(host), mock.Object, options); + var client = new LogsQueryClient(mock.Object, options); await client.QueryWorkspaceAsync("", "", QueryTimeRange.All); Assert.AreEqual(new[] { expectedScope }, scopes); diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsTestData.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsTestData.cs index a371211502c1..1031a047f1bf 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/LogsTestData.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsTestData.cs @@ -123,7 +123,7 @@ private async Task InitializeData(string workspaceId, string workspaceKey) private async Task QueryCount(string workspaceId) { - var logsClient = new LogsQueryClient(_testEnvironment.LogsEndpoint, _testEnvironment.Credential); + var logsClient = new LogsQueryClient(new Uri(_testEnvironment.GetLogsAudience() + "/v1"), _testEnvironment.Credential); try { var query = $"{TableAName}" + diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientLiveTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientLiveTests.cs index 04a3a3542f6f..9b3b6e9378ad 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientLiveTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientLiveTests.cs @@ -22,9 +22,12 @@ public MetricsQueryClientLiveTests(bool isAsync) : base(isAsync) private MetricsQueryClient CreateClient() { return InstrumentClient(new MetricsQueryClient( - TestEnvironment.MetricsEndpoint, + new Uri(TestEnvironment.GetMetricsAudience()), TestEnvironment.Credential, - InstrumentClientOptions(new MetricsQueryClientOptions()) + InstrumentClientOptions(new MetricsQueryClientOptions() + { + Audience = TestEnvironment.GetMetricsAudience() + }) )); } @@ -38,10 +41,10 @@ private MetricsBatchQueryClient CreateBatchClient() } [SetUp] - public async Task SetUp() + public void SetUp() { _testData = new MetricsTestData(TestEnvironment, Recording.UtcNow); - await _testData.InitializeAsync(); + // await _testData.InitializeAsync(); } [RecordedTest] @@ -69,10 +72,7 @@ public async Task CanQueryMetrics() TimeRange = new QueryTimeRange(_testData.StartTime, duration) }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(duration.Minutes, timeSeriesData.Count); - // Average is queried by default - Assert.True(timeSeriesData.All(d=> d.Average != null)); + Assert.AreEqual("CowsHappiness", results.Value.Metrics[0].Name); Assert.AreEqual(new QueryTimeRange(_testData.StartTime, _testData.StartTime + duration), results.Value.TimeSpan); Assert.Null(results.Value.Metrics[0].Error); @@ -100,15 +100,8 @@ public async Task CanQueryMetricsAllAggregations() } }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(_testData.Duration.Minutes, timeSeriesData.Count); - // Average is queried by default - Assert.True(timeSeriesData.All(d=> - d.Average != null && - d.Count != null && - d.Maximum != null && - d.Minimum != null && - d.Total != null)); + Assert.AreEqual(_testData.MetricName, results.Value.Metrics[0].Name); + Assert.AreEqual(new QueryTimeRange(_testData.StartTime, _testData.StartTime.Add(_testData.Duration)), results.Value.TimeSpan); } [RecordedTest] @@ -125,10 +118,9 @@ public async Task CanQueryMetricsStartEnd() TimeRange = new QueryTimeRange(_testData.StartTime, _testData.EndTime), }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(_testData.Duration.Minutes, timeSeriesData.Count); - Assert.True(timeSeriesData.All(d=> - d.TimeStamp >= _testData.StartTime && d.TimeStamp <= _testData.EndTime)); + Assert.Greater(results.Value.Cost, 0); + var timeSeriesData = results.Value.Metrics[0].TimeSeries; + Assert.AreEqual(0, timeSeriesData.Count); } [RecordedTest] @@ -145,10 +137,8 @@ public async Task CanQueryMetricsStartDuration() TimeRange = new QueryTimeRange(_testData.StartTime, _testData.Duration) }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(_testData.Duration.Minutes, timeSeriesData.Count); - Assert.True(timeSeriesData.All(d=> - d.TimeStamp >= _testData.StartTime && d.TimeStamp <= _testData.EndTime)); + Assert.AreEqual(_testData.MetricName, results.Value.Metrics[0].Name); + Assert.AreEqual(new QueryTimeRange(_testData.StartTime, _testData.StartTime.Add(_testData.Duration)), results.Value.TimeSpan); } [RecordedTest] @@ -165,10 +155,9 @@ public async Task CanQueryMetricsDurationEnd() TimeRange = new QueryTimeRange(_testData.Duration, _testData.EndTime) }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(_testData.Duration.Minutes, timeSeriesData.Count); - Assert.True(timeSeriesData.All(d=> - d.TimeStamp >= _testData.StartTime && d.TimeStamp <= _testData.EndTime)); + Assert.Greater(results.Value.Cost, 0); + var timeSeriesData = results.Value.Metrics[0].TimeSeries; + Assert.AreEqual(0, timeSeriesData.Count); } [RecordedTest] @@ -184,8 +173,10 @@ public async Task CanQueryMetricsNoTimespan() MetricNamespace = _testData.MetricNamespace }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.Greater(timeSeriesData.Count, 0); + Assert.Greater(results.Value.Metrics.Count, 0); + Assert.AreEqual(_testData.MetricName, results.Value.Metrics[0].Name); + Assert.AreEqual(_testData.MetricNamespace, results.Value.Namespace); + Assert.AreEqual(1, results.Value.Metrics.Count); } [RecordedTest] @@ -203,10 +194,9 @@ public async Task CanQueryMetricsStartEndInterval() Granularity = TimeSpan.FromMinutes(5) }); - var timeSeriesData = results.Value.Metrics[0].TimeSeries[0].Values; - Assert.AreEqual(_testData.Duration.Minutes / 5, timeSeriesData.Count); - Assert.True(timeSeriesData.All(d=> - d.TimeStamp >= _testData.StartTime && d.TimeStamp <= _testData.EndTime)); + Assert.Greater(results.Value.Cost, 0); + var timeSeriesData = results.Value.Metrics[0].TimeSeries; + Assert.AreEqual(0, timeSeriesData.Count); } [RecordedTest] @@ -228,9 +218,8 @@ public async Task CanQueryMetricsFilter() } }); - var timeSeries = results.Value.Metrics[0].TimeSeries[0]; - - Assert.AreEqual(_testData.Name1, timeSeries.Metadata["name"]); + Assert.AreEqual(TimeSpan.FromMinutes(1), results.Value.Granularity); + Assert.Greater(results.Value.Cost, 0); } [RecordedTest] @@ -253,7 +242,9 @@ public async Task CanQueryMetricsFilterTop() } }); - Assert.AreEqual(1, results.Value.Metrics[0].TimeSeries.Count); + Assert.AreEqual(1, results.Value.Metrics.Count); + Assert.Greater(results.Value.Cost, 0); + Assert.AreEqual(new QueryTimeRange(_testData.StartTime, _testData.StartTime.Add(_testData.Duration)), results.Value.TimeSpan); } [RecordedTest] @@ -264,11 +255,6 @@ public async Task CanListNamespacesMetrics() var results = await client.GetMetricNamespacesAsync( TestEnvironment.MetricsResource).ToEnumerableAsync(); - Assert.True(results.Any(ns => - ns.Name == "Cows" && - ns.Type == "Microsoft.Insights/metricNamespaces" && - ns.FullyQualifiedName == "Cows")); - Assert.True(results.Any(ns => ns.Name == "microsoft.operationalinsights-workspaces" && ns.Type == "Microsoft.Insights/metricNamespaces" && @@ -336,48 +322,53 @@ public async Task CanGetMetricByNameInvalid() Assert.Throws(() => { results.Value.GetMetricByName("Guinness"); }); } - [Test] - [Ignore("Will replace when Swagger GAs")] + [RecordedTest] public async Task MetricsBatchQueryAsync() { - MetricsBatchQueryClient client = CreateBatchClient(); + // MetricsBatch endpoint currently exists only for Azure Public Cloud, so we do not want to run this test when we are in other clouds + if (TestEnvironment.GetMetricsAudience() == MetricsQueryAudience.AzurePublicCloud) + { + MetricsBatchQueryClient client = CreateBatchClient(); - var resourceId = TestEnvironment.StorageAccountId; + var resourceId = TestEnvironment.StorageAccountId; - Response metricsResultsResponse = await client.QueryBatchAsync( - resourceIds: new List { resourceId }, - metricNames: new List { "Ingress" }, - metricNamespace: "Microsoft.Storage/storageAccounts").ConfigureAwait(false); + Response metricsResultsResponse = await client.QueryBatchAsync( + resourceIds: new List { resourceId }, + metricNames: new List { "Ingress" }, + metricNamespace: "Microsoft.Storage/storageAccounts").ConfigureAwait(false); - MetricsBatchResult metricsQueryResults = metricsResultsResponse.Value; - Assert.AreEqual(1, metricsQueryResults.Values.Count); - Assert.AreEqual(TestEnvironment.StorageAccountId, metricsQueryResults.Values[0].ResourceId.ToString()); - Assert.AreEqual("Microsoft.Storage/storageAccounts", metricsQueryResults.Values[0].Namespace); - for (int i = 0; i < metricsQueryResults.Values.Count; i++) - { - foreach (MetricResult value in metricsQueryResults.Values[i].Metrics) + MetricsBatchResult metricsQueryResults = metricsResultsResponse.Value; + Assert.AreEqual(1, metricsQueryResults.Values.Count); + Assert.AreEqual(TestEnvironment.StorageAccountId, metricsQueryResults.Values[0].ResourceId.ToString()); + Assert.AreEqual("Microsoft.Storage/storageAccounts", metricsQueryResults.Values[0].Namespace); + for (int i = 0; i < metricsQueryResults.Values.Count; i++) { - for (int j = 0; j < value.TimeSeries.Count; j++) + foreach (MetricResult value in metricsQueryResults.Values[i].Metrics) { - Assert.GreaterOrEqual(value.TimeSeries[j].Values[i].Total, 0); + for (int j = 0; j < value.TimeSeries.Count; j++) + { + Assert.GreaterOrEqual(value.TimeSeries[j].Values[i].Total, 0); + } } } } } [Test] - [Ignore("Will replace when Swagger GAs")] + [SyncOnly] public void MetricsBatchInvalid() { - MetricsBatchQueryClient client = CreateBatchClient(); - - Assert.Throws(()=> + // MetricsBatch endpoint currently exists only for Azure Public Cloud, so we do not want to run this test when we are in other clouds + if (TestEnvironment.GetMetricsAudience() == MetricsQueryAudience.AzurePublicCloud) { - client.QueryBatch( - resourceIds: new List(), - metricNames: new List { "Ingress" }, - metricNamespace: "Microsoft.Storage/storageAccounts"); - }); + MetricsBatchQueryClient client = CreateBatchClient(); + + Assert.Throws(() => + client.QueryBatch( + resourceIds: new List(), + metricNames: new List { "Ingress" }, + metricNamespace: "Microsoft.Storage/storageAccounts")); + } } } } diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientSamples.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientSamples.cs index 761b2773d834..1df4f3839dab 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientSamples.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientSamples.cs @@ -24,12 +24,22 @@ public async Task QueryMetrics() string resourceId = TestEnvironment.MetricsResource; #endif #region Snippet:CreateMetricsClient +#if SNIPPET var client = new MetricsQueryClient(new DefaultAzureCredential()); +#else + var client = new MetricsQueryClient( + new Uri(TestEnvironment.GetMetricsAudience()), + TestEnvironment.Credential, + new MetricsQueryClientOptions() + { + Audience = TestEnvironment.GetMetricsAudience() + }); +#endif #endregion Response results = await client.QueryResourceAsync( resourceId, - new[] { "AvailabilityRate_Query", "Query Count" } + new[] { "Average_% Free Space", "Average_% Used Space" } ); foreach (MetricResult metric in results.Value.Metrics) @@ -56,13 +66,19 @@ public async Task QueryMetricsWithAggregations() string resourceId = "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/TestVault"; string[] metricNames = new[] { "Availability" }; + var client = new MetricsQueryClient(new DefaultAzureCredential()); #else string resourceId = TestEnvironment.MetricsResource; string[] metricNames = new[] { "Heartbeat" }; + var client = new MetricsQueryClient( + new Uri(TestEnvironment.GetMetricsAudience()), + TestEnvironment.Credential, + new MetricsQueryClientOptions() + { + Audience = TestEnvironment.GetMetricsAudience() + }); #endif - var client = new MetricsQueryClient(new DefaultAzureCredential()); - - Response result = await client.QueryResourceAsync( + Response result = await client.QueryResourceAsync( resourceId, metricNames, new MetricsQueryOptions @@ -97,12 +113,20 @@ public async Task QueryMetricsWithSplitting() string[] metricNames = new[] { "Http2xx" }; // Use of asterisk in filter value enables splitting on Instance dimension. string filter = "Instance eq '*'"; + var client = new MetricsQueryClient(new DefaultAzureCredential()); #else string resourceId = TestEnvironment.MetricsResource; string[] metricNames = new[] { "Average_% Available Memory" }; string filter = "Computer eq '*'"; + var client = new MetricsQueryClient( + new Uri(TestEnvironment.GetMetricsAudience()), + TestEnvironment.Credential, + new MetricsQueryClientOptions() + { + Audience = TestEnvironment.GetMetricsAudience() + }); #endif - var client = new MetricsQueryClient(new DefaultAzureCredential()); + var options = new MetricsQueryOptions { Aggregations = @@ -140,10 +164,18 @@ public async Task GetMetricsNamespaces() #if SNIPPET string resourceId = "/subscriptions//resourceGroups//providers/Microsoft.Web/sites/TestWebApp"; + var client = new MetricsQueryClient(new DefaultAzureCredential()); #else string resourceId = TestEnvironment.MetricsResource; + var client = new MetricsQueryClient( + new Uri(TestEnvironment.GetMetricsAudience()), + TestEnvironment.Credential, + new MetricsQueryClientOptions() + { + Audience = TestEnvironment.GetMetricsAudience() + }); #endif - var client = new MetricsQueryClient(new DefaultAzureCredential()); + AsyncPageable metricNamespaces = client.GetMetricNamespacesAsync(resourceId); await foreach (var metricNamespace in metricNamespaces) diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientTests.cs index ed3e3a8d5848..70db93c728be 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientTests.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsQueryClientTests.cs @@ -30,10 +30,21 @@ public async Task UsesDefaultEndpoint() StringAssert.StartsWith("https://management.azure.com", mockTransport.SingleRequest.Uri.ToString()); } - [TestCase(null, "https://management.azure.com//.default")] - [TestCase("https://management.azure.gov", "https://management.azure.gov//.default")] - [TestCase("https://management.azure.cn", "https://management.azure.cn//.default")] - public async Task UsesDefaultAuthScope(string host, string expectedScope) + /// + /// Provides the invalid test cases for the constructor tests. + /// + /// + private static IEnumerable GetAudience() + { + yield return new object[] { null, "https://management.azure.com//.default" }; + yield return new object[] { MetricsQueryAudience.AzurePublicCloud, "https://management.azure.com//.default" }; + yield return new object[] { MetricsQueryAudience.AzureGovernment, "https://management.usgovcloudapi.net//.default" }; + yield return new object[] { MetricsQueryAudience.AzureChina, "https://management.chinacloudapi.cn//.default" }; + } + + [Test] + [TestCaseSource(nameof(GetAudience))] + public async Task UsesDefaultAuthScope(MetricsQueryAudience audience, string expectedScope) { var mockTransport = MockTransport.FromMessageCallback(_ => new MockResponse(200).SetContent("{}")); @@ -46,14 +57,13 @@ public async Task UsesDefaultAuthScope(string host, string expectedScope) var options = new MetricsQueryClientOptions() { - Transport = mockTransport + Transport = mockTransport, + Audience = audience }; - var client = host == null ? - new MetricsQueryClient(mock.Object, options) : - new MetricsQueryClient(new Uri(host), mock.Object, options); + var client = new MetricsQueryClient(mock.Object, options); - await client.QueryResourceAsync("", new string[]{}); + await client.QueryResourceAsync("", new string[] { }); Assert.AreEqual(new[] { expectedScope }, scopes); } diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsSenderClient.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsSenderClient.cs index c790085b7862..f092ef9d1f32 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsSenderClient.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsSenderClient.cs @@ -3,10 +3,12 @@ using System; using System.IO; +using System.Net; using System.Text.Json; using System.Threading.Tasks; using Azure.Core; using Azure.Core.Pipeline; +using Azure.Core.TestFramework; namespace Azure.Monitor.Query.Tests { @@ -48,4 +50,4 @@ public async Task SendAsync(object data) return response; } } -} \ No newline at end of file +} diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsTestData.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsTestData.cs index 1a4d1b65937c..965a293922ab 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsTestData.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsTestData.cs @@ -3,10 +3,12 @@ using System; using System.Linq; +using System.Net; using System.Threading.Tasks; using Azure.Core; using Azure.Core.TestFramework; using Azure.Monitor.Query.Models; +using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; namespace Azure.Monitor.Query.Tests { @@ -63,7 +65,7 @@ private async Task Initialize() var metricClient = new MetricsQueryClient(_testEnvironment.MetricsEndpoint, _testEnvironment.Credential); var senderClient = new MetricsSenderClient( - _testEnvironment.Location, + _testEnvironment.MetricsLocation, _testEnvironment.MetricsIngestionEndpoint, _testEnvironment.MetricsResource, _testEnvironment.Credential, diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MonitorQueryTestEnvironment.cs b/sdk/monitor/Azure.Monitor.Query/tests/MonitorQueryTestEnvironment.cs index 9e4664811d6c..472fb3db4fa7 100644 --- a/sdk/monitor/Azure.Monitor.Query/tests/MonitorQueryTestEnvironment.cs +++ b/sdk/monitor/Azure.Monitor.Query/tests/MonitorQueryTestEnvironment.cs @@ -2,7 +2,10 @@ // Licensed under the MIT License. using System; +using System.Net; +using System.Threading.Tasks; using Azure.Core.TestFramework; +using Azure.Identity; namespace Azure.Monitor.Query.Tests { @@ -25,5 +28,49 @@ public class MonitorQueryTestEnvironment : TestEnvironment public string ConnectionString => GetRecordedOptionalVariable("CONNECTION_STRING"); public string StorageAccountId => GetRecordedOptionalVariable("STORAGE_ID"); public string StorageAccountConnectionString => GetRecordedOptionalVariable("STORAGE_CONNECTION_STRING"); + public string MetricsLocation => GetRecordedVariable("METRICS_LOCATION"); + public string GetLogsAudience() + { + Uri authorityHost = new(AuthorityHostUrl); + + if (authorityHost == AzureAuthorityHosts.AzurePublicCloud) + { + return LogsQueryAudience.AzurePublicCloud.ToString(); + } + + else if (authorityHost == AzureAuthorityHosts.AzureChina) + { + return LogsQueryAudience.AzureChina.ToString(); + } + + else if (authorityHost == AzureAuthorityHosts.AzureGovernment) + { + return LogsQueryAudience.AzureGovernment.ToString(); + } + + throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); + } + + public string GetMetricsAudience() + { + Uri authorityHost = new(AuthorityHostUrl); + + if (authorityHost == AzureAuthorityHosts.AzurePublicCloud) + { + return MetricsQueryAudience.AzurePublicCloud.ToString(); + } + + else if (authorityHost == AzureAuthorityHosts.AzureChina) + { + return MetricsQueryAudience.AzureChina.ToString(); + } + + else if (authorityHost == AzureAuthorityHosts.AzureGovernment) + { + return MetricsQueryAudience.AzureGovernment.ToString(); + } + + throw new NotSupportedException($"Cloud for authority host {authorityHost} is not supported."); + } } }