Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update cloud configuration API #23141

Merged
merged 25 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2ee746a
changes to test configuration files
annelo-msft Jul 14, 2021
fe648b7
Merge remote-tracking branch 'upstream/main' into acr-issue-21236
annelo-msft Jul 14, 2021
cd7e617
designate cloud environment and pass in authority scope
annelo-msft Jul 14, 2021
9574936
small test fixes
annelo-msft Jul 14, 2021
4516355
working toward ignoring anonymous access tests in national clouds
annelo-msft Jul 16, 2021
61a6a3b
Merge remote-tracking branch 'upstream/main' into acr-issue-21556
annelo-msft Jul 16, 2021
24ef4d5
update logic for anonymous client
annelo-msft Jul 19, 2021
e9c8d45
experimental API for specifying ACR audience
annelo-msft Aug 2, 2021
5eecbfd
Merge remote-tracking branch 'upstream/main' into acr-audience-exp1
annelo-msft Aug 5, 2021
9c539bd
swagger updates
annelo-msft Aug 5, 2021
cd071b2
update audience to extensible enum
annelo-msft Aug 5, 2021
d29e9f5
fix build
annelo-msft Aug 5, 2021
5f86df3
updates
annelo-msft Aug 5, 2021
1ca5cfc
Merge remote-tracking branch 'upstream/main' into acr-issue-21556
annelo-msft Aug 6, 2021
85a414e
Merge remote-tracking branch 'upstream/main' into acr-audience-exp1
annelo-msft Aug 6, 2021
370475e
add tests for audience
annelo-msft Aug 6, 2021
d1f00ad
update track 1 mgmt plane library base url
annelo-msft Aug 6, 2021
d99966d
update tests to use new constructor pattern
annelo-msft Aug 6, 2021
b64e2ce
add recorded tests
annelo-msft Aug 6, 2021
69b468e
update samples
annelo-msft Aug 6, 2021
d889ee0
update recorded tests
annelo-msft Aug 6, 2021
0524f9d
don't test samples in national clouds
annelo-msft Aug 6, 2021
ea9d2b3
update enum names per pr fb
annelo-msft Aug 6, 2021
c28f495
update enum names per pr fb
annelo-msft Aug 6, 2021
f114cce
update docstring for Audience property
annelo-msft Aug 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ Iterate through the collection of repositories in the registry.
Uri endpoint = new Uri(Environment.GetEnvironmentVariable("REGISTRY_ENDPOINT"));

// Create a new ContainerRegistryClient
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential(),
new ContainerRegistryClientOptions()
{
Audience = ContainerRegistryAudience.AzurePublicCloud
});

// Get the collection of repository names from the registry
Pageable<string> repositories = client.GetRepositoryNames();
Expand Down Expand Up @@ -297,7 +301,7 @@ await foreach (string repositoryName in repositoryNames)
To authenticate with a registry in a [National Cloud](https://docs.microsoft.com/azure/active-directory/develop/authentication-national-cloud), you will need to make the following additions to your client configuration:

- Set the `AuthorityHost` in the credential options or via the `AZURE_AUTHORITY_HOST` environment variable
- Set the `AuthenticationScope` in `ContainerRegistryClientOptions`
- Set the `Audience` in `ContainerRegistryClientOptions`

```C#
// Create a ContainerRegistryClient that will authenticate through AAD in the China national cloud
Expand All @@ -310,7 +314,7 @@ ContainerRegistryClient client = new ContainerRegistryClient(endpoint,
}),
new ContainerRegistryClientOptions()
{
AuthenticationScope = "https://management.chinacloudapi.cn/.default"
Audience = ContainerRegistryAudience.AzurePublicCloud
});
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ public ArtifactTagProperties() { }
public string RegistryLoginServer { get { throw null; } }
public string RepositoryName { get { throw null; } }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ContainerRegistryAudience : System.IEquatable<Azure.Containers.ContainerRegistry.ContainerRegistryAudience>
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public ContainerRegistryAudience(string value) { throw null; }
public static Azure.Containers.ContainerRegistry.ContainerRegistryAudience AzureChina { get { throw null; } }
public static Azure.Containers.ContainerRegistry.ContainerRegistryAudience AzureGermany { get { throw null; } }
public static Azure.Containers.ContainerRegistry.ContainerRegistryAudience AzureGovernment { get { throw null; } }
public static Azure.Containers.ContainerRegistry.ContainerRegistryAudience AzurePublicCloud { get { throw null; } }
public bool Equals(Azure.Containers.ContainerRegistry.ContainerRegistryAudience 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.Containers.ContainerRegistry.ContainerRegistryAudience left, Azure.Containers.ContainerRegistry.ContainerRegistryAudience right) { throw null; }
public static implicit operator Azure.Containers.ContainerRegistry.ContainerRegistryAudience (string value) { throw null; }
public static bool operator !=(Azure.Containers.ContainerRegistry.ContainerRegistryAudience left, Azure.Containers.ContainerRegistry.ContainerRegistryAudience right) { throw null; }
public override string ToString() { throw null; }
}
public partial class ContainerRegistryClient
{
protected ContainerRegistryClient() { }
Expand All @@ -128,7 +148,7 @@ public ContainerRegistryClient(System.Uri endpoint, Azure.Core.TokenCredential c
public partial class ContainerRegistryClientOptions : Azure.Core.ClientOptions
{
public ContainerRegistryClientOptions(Azure.Containers.ContainerRegistry.ContainerRegistryClientOptions.ServiceVersion version = Azure.Containers.ContainerRegistry.ContainerRegistryClientOptions.ServiceVersion.V1_0) { }
public string AuthenticationScope { get { throw null; } set { } }
public Azure.Containers.ContainerRegistry.ContainerRegistryAudience? Audience { get { throw null; } set { } }
public enum ServiceVersion
{
V1_0 = 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ Create a `ContainerRegistryClient` and send a request.
Uri endpoint = new Uri(Environment.GetEnvironmentVariable("REGISTRY_ENDPOINT"));

// Create a new ContainerRegistryClient
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential(),
new ContainerRegistryClientOptions()
{
Audience = ContainerRegistryAudience.AzurePublicCloud
});

// Get the collection of repository names from the registry
Pageable<string> repositories = client.GetRepositoryNames();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,20 @@ public ContainerRegistryClient(Uri endpoint, TokenCredential credential, Contain
Argument.AssertNotNull(credential, nameof(credential));
Argument.AssertNotNull(options, nameof(options));

if (options.Audience == null)
{
throw new InvalidOperationException("ContainerRegistryClientOptions.Audience property must be set to initialize ContainerRegistryClient.");
}

_endpoint = endpoint;
_registryName = endpoint.Host.Split('.')[0];
_clientDiagnostics = new ClientDiagnostics(options);

_acrAuthPipeline = HttpPipelineBuilder.Build(options);
_acrAuthClient = new AuthenticationRestClient(_clientDiagnostics, _acrAuthPipeline, endpoint.AbsoluteUri);

_pipeline = HttpPipelineBuilder.Build(options, new ContainerRegistryChallengeAuthenticationPolicy(credential, options.AuthenticationScope, _acrAuthClient));
string defaultScope = options.Audience + "/.default";
_pipeline = HttpPipelineBuilder.Build(options, new ContainerRegistryChallengeAuthenticationPolicy(credential, defaultScope, _acrAuthClient));
_restClient = new ContainerRegistryRestClient(_clientDiagnostics, _pipeline, _endpoint.AbsoluteUri);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,8 @@ public class ContainerRegistryClientOptions : ClientOptions
internal string Version { get; }

/// <summary>
/// Gets or sets the authentication scope to use for authentication with AAD.
/// This defaults to the Azure Resource Manager "Azure Global" scope. To
/// connect to a different cloud, set this value to "&lt;resource-id&gt;/.default",
/// where &lt;resource-id&gt; is one of the Resource IDs listed at
/// https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/services-support-managed-identities#azure-resource-manager.
/// For example, to connect to the Azure Germany cloud, create a client with
/// <see cref="AuthenticationScope"/> set to "https://management.microsoftazure.de/.default".
/// </summary>
public string AuthenticationScope { get; set; } = "https://management.azure.com/.default";
public ContainerRegistryAudience? Audience { get; set; }
annelo-msft marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the doc comments have been deleted - was that intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not! Checking...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good catch! I took out the doc comment for AuthenticationScope since it was going away, but I forgot to add one back in for Audience. Thanks!


/// <summary>
/// Create an instance of the options for configuring request sent to the Container Registry service.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.ComponentModel;

namespace Azure.Containers.ContainerRegistry
{
/// <summary> Cloud audiences available for ACR. </summary>
public readonly partial struct ContainerRegistryAudience : IEquatable<ContainerRegistryAudience>
{
private readonly string _value;

/// <summary> Determines if two <see cref="ContainerRegistryAudience"/> values are the same. </summary>
/// <exception cref="ArgumentNullException"> <paramref name="value"/> is null. </exception>
public ContainerRegistryAudience(string value)
{
_value = value ?? throw new ArgumentNullException(nameof(value));
}

private const string AzureChinaValue = "https://management.chinacloudapi.cn";
private const string AzureGermanyValue = "https://management.microsoftazure.de";
private const string AzureGovernmentValue = "https://management.usgovcloudapi.net";
private const string AzurePublicCloudValue = "https://management.azure.com";

/// <summary> Azure China. </summary>
public static ContainerRegistryAudience AzureChina { get; } = new ContainerRegistryAudience(AzureChinaValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the values of this going to change once they add ACR specific scopes? If not should we name these something like ArmChina or something that denotes that these are the ARM audience so we don't steal the good name from what we eventually want users to choose (the ACR specific scope)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to be AzureResourceManagerChina. Let me know if this doesn't sound good to you!


/// <summary> Azure Germany. </summary>
public static ContainerRegistryAudience AzureGermany { get; } = new ContainerRegistryAudience(AzureGermanyValue);

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

/// <summary> Azure Public Cloud. </summary>
public static ContainerRegistryAudience AzurePublicCloud { get; } = new ContainerRegistryAudience(AzurePublicCloudValue);
annelo-msft marked this conversation as resolved.
Show resolved Hide resolved

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

/// <inheritdoc />
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => obj is ContainerRegistryAudience other && Equals(other);
/// <inheritdoc />
public bool Equals(ContainerRegistryAudience 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,25 @@ public ContainerRegistryRecordedTestBase(bool isAsync, RecordedTestMode mode) :
Sanitizer = new ContainerRegistryRecordedTestSanitizer();
}

public ContainerRegistryClient CreateClient(bool anonymousAccess = false, string authenticationScope = null)
public ContainerRegistryClient CreateClient(ContainerRegistryAudience audience, bool anonymousAccess = false)
{
return anonymousAccess ?

InstrumentClient(new ContainerRegistryClient(
new Uri(TestEnvironment.AnonymousAccessEndpoint),
InstrumentClientOptions(new ContainerRegistryClientOptions())
InstrumentClientOptions(new ContainerRegistryClientOptions()
{
Audience = audience
})
)) :

InstrumentClient(new ContainerRegistryClient(
new Uri(TestEnvironment.Endpoint),
TestEnvironment.Credential,
InstrumentClientOptions(new ContainerRegistryClientOptions())
InstrumentClientOptions(new ContainerRegistryClientOptions()
{
Audience = audience
})
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ public void CreateClient()
Uri endpoint = new Uri(Environment.GetEnvironmentVariable("REGISTRY_ENDPOINT"));

// Create a new ContainerRegistryClient
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());
ContainerRegistryClient client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential(),
new ContainerRegistryClientOptions()
{
Audience = ContainerRegistryAudience.AzurePublicCloud
});

// Get the collection of repository names from the registry
Pageable<string> repositories = client.GetRepositoryNames();
Expand Down