Skip to content

Commit

Permalink
[Azure.Monitor.Query] Add sovereign/government cloud support (#41653)
Browse files Browse the repository at this point in the history
  • Loading branch information
nisha-bhatia authored Feb 10, 2024
1 parent e4ca428 commit 7ebbbd0
Show file tree
Hide file tree
Showing 22 changed files with 404 additions and 115 deletions.
1 change: 1 addition & 0 deletions sdk/monitor/Azure.Monitor.Query/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
### Breaking Changes

### Bugs Fixed
- Enable national cloud support for US Gov and China clouds

### Other Changes

Expand Down
9 changes: 6 additions & 3 deletions sdk/monitor/Azure.Monitor.Query/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ var client = new MetricsQueryClient(new DefaultAzureCredential());

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)
Expand Down Expand Up @@ -522,8 +522,7 @@ string resourceId =
"/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.KeyVault/vaults/TestVault";
string[] metricNames = new[] { "Availability" };
var client = new MetricsQueryClient(new DefaultAzureCredential());

Response<MetricsQueryResult> result = await client.QueryResourceAsync(
Response <MetricsQueryResult> result = await client.QueryResourceAsync(
resourceId,
metricNames,
new MetricsQueryOptions
Expand Down Expand Up @@ -555,6 +554,7 @@ To programmatically retrieve metrics namespaces, use the following code:
string resourceId =
"/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.Web/sites/TestWebApp";
var client = new MetricsQueryClient(new DefaultAzureCredential());

AsyncPageable<MetricNamespace> metricNamespaces = client.GetMetricNamespacesAsync(resourceId);

await foreach (var metricNamespace in metricNamespaces)
Expand All @@ -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 =
Expand Down Expand Up @@ -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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Azure.Monitor.Query.LogsQueryAudience>
{
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() { }
Expand All @@ -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,
Expand All @@ -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<Azure.Monitor.Query.Models.MetricsBatchResult> QueryBatch(System.Collections.Generic.List<string> resourceIds, System.Collections.Generic.List<string> 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<Azure.Response<Azure.Monitor.Query.Models.MetricsBatchResult>> QueryBatchAsync(System.Collections.Generic.List<string> resourceIds, System.Collections.Generic.List<string> 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<Azure.Monitor.Query.MetricsQueryAudience>
{
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() { }
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion sdk/monitor/Azure.Monitor.Query/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
10 changes: 6 additions & 4 deletions sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public LogsQueryClient(TokenCredential credential) : this(credential, null)
}

/// <summary>
/// Initializes a new instance of <see cref="LogsQueryClient"/>. Uses the default 'https://api.loganalytics.io' endpoint.
/// Initializes a new instance of <see cref="LogsQueryClient"/>. Uses the default 'https://api.loganalytics.io' endpoint if Audience is not set in LogsQueryClientOptions.
/// </summary>
/// <param name="credential">The <see cref="TokenCredential"/> instance to use for authentication.</param>
/// <param name="options">The <see cref="LogsQueryClientOptions"/> instance to use as client configuration.</param>
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)
{
}

Expand All @@ -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<string> { 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);
}

Expand Down
6 changes: 6 additions & 0 deletions sdk/monitor/Azure.Monitor.Query/src/LogsQueryClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,11 @@ internal string GetVersionString()
_ => throw new ArgumentException(@"Unknown version {_version}")
};
}

/// <summary>
/// Gets or sets the audience to use for authentication with Microsoft Entra ID. The audience is not considered when using a shared key.
/// </summary>
/// <value>If <c>null</c>, <see cref="LogsQueryAudience.AzurePublicCloud" /> will be assumed.</value>
public LogsQueryAudience? Audience { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Azure.Monitor.Query
/// <summary>
/// The <see cref="MetricsBatchQueryClient"/> allows you to query multiple Azure Monitor Metric services.
/// </summary>
internal class MetricsBatchQueryClient
public class MetricsBatchQueryClient
{
private readonly MetricsBatchRestClient _metricBatchClient;
private readonly ClientDiagnostics _clientDiagnostics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Azure.Monitor.Query
/// <summary>
/// Provides the client configuration options for connecting to Azure Monitor Metrics service.
/// </summary>
internal class MetricsBatchQueryClientOptions: ClientOptions
public class MetricsBatchQueryClientOptions: ClientOptions
{
private readonly ServiceVersion _version;

Expand Down
15 changes: 8 additions & 7 deletions sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public MetricsQueryClient(TokenCredential credential) : this(credential, null)
}

/// <summary>
/// Initializes a new instance of <see cref="MetricsQueryClient"/>. Uses the default 'https://management.azure.com' endpoint.
/// Initializes a new instance of <see cref="MetricsQueryClient"/>. Uses the default 'https://management.azure.com' endpoint if Audience is not set in MetricsQueryClientOptions.
/// </summary>
/// <param name="credential">The <see cref="TokenCredential"/> instance to use for authentication.</param>
/// <param name="options">The <see cref="MetricsQueryClientOptions"/> instance to as client configuration.</param>
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)
{
}

Expand All @@ -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<string> { 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);
Expand Down Expand Up @@ -90,7 +91,7 @@ protected MetricsQueryClient()
///
/// Response&lt;MetricsQueryResult&gt; results = await client.QueryResourceAsync(
/// resourceId,
/// new[] { &quot;AvailabilityRate_Query&quot;, &quot;Query Count&quot; }
/// new[] { &quot;Average_% Free Space&quot;, &quot;Average_% Used Space&quot; }
/// );
///
/// foreach (MetricResult metric in results.Value.Metrics)
Expand Down Expand Up @@ -151,7 +152,7 @@ public virtual Response<MetricsQueryResult> QueryResource(string resourceId, IEn
///
/// Response&lt;MetricsQueryResult&gt; results = await client.QueryResourceAsync(
/// resourceId,
/// new[] { &quot;AvailabilityRate_Query&quot;, &quot;Query Count&quot; }
/// new[] { &quot;Average_% Free Space&quot;, &quot;Average_% Used Space&quot; }
/// );
///
/// foreach (MetricResult metric in results.Value.Metrics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,11 @@ public enum ServiceVersion
V2018_01_01 = 1,
#pragma warning restore CA1707 // Identifiers should not contain underscores
}

/// <summary>
/// Gets or sets the audience to use for authentication with Microsoft Entra ID. The audience is not considered when using a shared key.
/// </summary>
/// <value>If <c>null</c>, <see cref="MetricsQueryAudience.AzurePublicCloud" /> will be assumed.</value>
public MetricsQueryAudience? Audience { get; set; }
}
}
59 changes: 59 additions & 0 deletions sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryAudience.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary> Cloud audiences available for Query. </summary>
public readonly partial struct LogsQueryAudience : IEquatable<LogsQueryAudience>
{
private readonly string _value;

/// <summary>
/// Initializes a new instance of the <see cref="LogsQueryAudience"/> object.
/// </summary>
/// <param name="value">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: <see href="https://learn.microsoft.com/en-us/azure/azure-government/documentation-government-manage-oms" />.</param>
/// <exception cref="ArgumentNullException"> <paramref name="value"/> is null. </exception>
/// <remarks>Use one of the constant members over creating a custom value, unless you have special needs for doing so.</remarks>
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";

/// <summary> Azure China. </summary>
public static LogsQueryAudience AzureChina { get; } = new LogsQueryAudience(AzureChinaValue);

/// <summary> Azure US Government. </summary>
public static LogsQueryAudience AzureGovernment { get; } = new LogsQueryAudience(AzureGovernmentValue);

/// <summary> Azure Public Cloud. </summary>
public static LogsQueryAudience AzurePublicCloud { get; } = new LogsQueryAudience(AzurePublicCloudValue);

/// <summary> Determines if two <see cref="LogsQueryAudience"/> values are the same. </summary>
public static bool operator ==(LogsQueryAudience left, LogsQueryAudience right) => left.Equals(right);
/// <summary> Determines if two <see cref="LogsQueryAudience"/> values are not the same. </summary>
public static bool operator !=(LogsQueryAudience left, LogsQueryAudience right) => !left.Equals(right);
/// <summary> Converts a string to a <see cref="LogsQueryAudience"/>. </summary>
public static implicit operator LogsQueryAudience(string value) => new LogsQueryAudience(value);

/// <inheritdoc />
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => obj is LogsQueryAudience other && Equals(other);
/// <inheritdoc />
public bool Equals(LogsQueryAudience other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase);

/// <inheritdoc />
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => _value?.GetHashCode() ?? 0;
/// <inheritdoc />
public override string ToString() => _value;
}
}
Loading

0 comments on commit 7ebbbd0

Please sign in to comment.