diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/api/Azure.Containers.ContainerRegistry.netstandard2.0.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/api/Azure.Containers.ContainerRegistry.netstandard2.0.cs index 7397252aaf10..a27f95b5d015 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/api/Azure.Containers.ContainerRegistry.netstandard2.0.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/api/Azure.Containers.ContainerRegistry.netstandard2.0.cs @@ -212,3 +212,99 @@ protected RegistryArtifact() { } public virtual System.Threading.Tasks.Task> UpdateTagPropertiesAsync(string tag, Azure.Containers.ContainerRegistry.ArtifactTagProperties value, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } } +namespace Azure.Containers.ContainerRegistry.Specialized +{ + public partial class ArtifactBlobProperties + { + internal ArtifactBlobProperties() { } + public string Digest { get { throw null; } } + public string FileName { get { throw null; } } + public string RepositoryName { get { throw null; } } + } + public partial class ContainerRegistryBlobClient + { + protected ContainerRegistryBlobClient() { } + public ContainerRegistryBlobClient(System.Uri endpoint, Azure.Core.TokenCredential credential, string repository) { } + public ContainerRegistryBlobClient(System.Uri endpoint, Azure.Core.TokenCredential credential, string repository, Azure.Containers.ContainerRegistry.ContainerRegistryClientOptions options) { } + public virtual Azure.Response DeleteBlob(string digest, Azure.Containers.ContainerRegistry.Specialized.DeleteBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteBlobAsync(string digest, Azure.Containers.ContainerRegistry.Specialized.DeleteBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteManifest(string digest, Azure.Containers.ContainerRegistry.Specialized.DeleteManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteManifestAsync(string digest, Azure.Containers.ContainerRegistry.Specialized.DeleteManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DownloadBlob(string digest, Azure.Containers.ContainerRegistry.Specialized.DownloadBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> DownloadBlobAsync(string digest, Azure.Containers.ContainerRegistry.Specialized.DownloadBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DownloadManifest(string digest, Azure.Containers.ContainerRegistry.Specialized.DownloadManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> DownloadManifestAsync(string digest, Azure.Containers.ContainerRegistry.Specialized.DownloadManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UploadBlob(System.IO.Stream stream, Azure.Containers.ContainerRegistry.Specialized.UploadBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> UploadBlobAsync(System.IO.Stream stream, Azure.Containers.ContainerRegistry.Specialized.UploadBlobOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UploadManifest(System.IO.Stream stream, Azure.Containers.ContainerRegistry.Specialized.UploadManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> UploadManifestAsync(System.IO.Stream stream, Azure.Containers.ContainerRegistry.Specialized.UploadManifestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } + public partial class DeleteBlobOptions + { + public DeleteBlobOptions() { } + } + public partial class DeleteManifestOptions + { + public DeleteManifestOptions() { } + } + public partial class DownloadBlobOptions + { + public DownloadBlobOptions() { } + } + public partial class DownloadBlobResult + { + public DownloadBlobResult(string digest, System.IO.Stream content) { } + public System.IO.Stream Content { get { throw null; } } + public string Digest { get { throw null; } } + } + public partial class DownloadManifestOptions + { + public DownloadManifestOptions() { } + public Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType MediaType { get { throw null; } set { } } + } + public partial class DownloadManifestResult + { + internal DownloadManifestResult() { } + public System.Collections.Generic.IReadOnlyList ArtifactFiles { get { throw null; } } + public System.IO.Stream Content { get { throw null; } } + public string Digest { get { throw null; } } + public Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType MediaType { get { throw null; } } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct ManifestMediaType : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public static readonly Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType OciManifest; + public bool Equals(Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType 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.Specialized.ManifestMediaType left, Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType right) { throw null; } + public static explicit operator string (Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType mediaType) { throw null; } + public static implicit operator Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType (string mediaType) { throw null; } + public static bool operator !=(Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType left, Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType right) { throw null; } + public override string ToString() { throw null; } + } + public partial class UploadBlobOptions + { + public UploadBlobOptions() { } + } + public partial class UploadBlobResult + { + internal UploadBlobResult() { } + public string Digest { get { throw null; } } + } + public partial class UploadManifestOptions + { + public UploadManifestOptions() { } + public Azure.Containers.ContainerRegistry.Specialized.ManifestMediaType MediaType { get { throw null; } set { } } + public string Tag { get { throw null; } set { } } + } + public partial class UploadManifestResult + { + internal UploadManifestResult() { } + public string Digest { get { throw null; } } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Artifact/RegistryArtifact.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Artifact/RegistryArtifact.cs index 9891ef260ab9..dda16cddf941 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Artifact/RegistryArtifact.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Artifact/RegistryArtifact.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -19,6 +21,7 @@ public partial class RegistryArtifact { private readonly ClientDiagnostics _clientDiagnostics; private readonly ContainerRegistryRestClient _restClient; + private readonly ContainerRegistryBlobRestClient _blobRestClient; private readonly Uri _registryEndpoint; private readonly string _repositoryName; @@ -44,7 +47,7 @@ public partial class RegistryArtifact /// /// - internal RegistryArtifact(Uri registryEndpoint, string repositoryName, string tagOrDigest, ClientDiagnostics clientDiagnostics, ContainerRegistryRestClient restClient) + internal RegistryArtifact(Uri registryEndpoint, string repositoryName, string tagOrDigest, ClientDiagnostics clientDiagnostics, ContainerRegistryRestClient restClient, ContainerRegistryBlobRestClient blobRestClient) { _repositoryName = repositoryName; _tagOrDigest = tagOrDigest; @@ -53,6 +56,7 @@ internal RegistryArtifact(Uri registryEndpoint, string repositoryName, string ta _clientDiagnostics = clientDiagnostics; _restClient = restClient; + _blobRestClient = blobRestClient; } /// Initializes a new instance of RegistryArtifact for mocking. diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj index 055e4a52997a..a4f93aec0b1f 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj @@ -8,7 +8,6 @@ - @@ -28,5 +27,8 @@ + + + diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactBlobProperties.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactBlobProperties.cs new file mode 100644 index 000000000000..3b17021fa764 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactBlobProperties.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class ArtifactBlobProperties + { + internal ArtifactBlobProperties(string repositoryName, string digest, string fileName = default) + { + RepositoryName = repositoryName; + Digest = digest; + FileName = fileName; + } + + /// + /// + public string Digest { get; } + + /// + /// + public string RepositoryName { get; } + + /// + /// Optional property - use Digest if FileName is null. + /// + public string FileName { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactManifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactManifest.cs new file mode 100644 index 000000000000..1cbaccebba97 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ArtifactManifest.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + [CodeGenModel("Manifest")] + internal partial class ArtifactManifest + { + /// Media type for this Manifest. + public string MediaType { get; set; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContainerRegistryBlobClient.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContainerRegistryBlobClient.cs new file mode 100644 index 000000000000..a453518c1958 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContainerRegistryBlobClient.cs @@ -0,0 +1,354 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class ContainerRegistryBlobClient + { + private readonly Uri _endpoint; + private readonly string _registryName; + private readonly string _repositoryName; + private readonly HttpPipeline _pipeline; + private readonly HttpPipeline _acrAuthPipeline; + private readonly ClientDiagnostics _clientDiagnostics; + private readonly ContainerRegistryRestClient _restClient; + private readonly AuthenticationRestClient _acrAuthClient; + private readonly ContainerRegistryBlobRestClient _blobRestClient; + + // TODO: Design choice about taking repository name in the constructor, vs. methods? + + /// + /// Initializes a new instance of the for managing container images and artifacts. + /// + /// The URI endpoint of the container registry. This is likely to be similar + /// to "https://{registry-name}.azurecr.io". + /// The API key credential used to authenticate requests + /// against the container registry. + /// + /// Thrown when the or is null. + public ContainerRegistryBlobClient(Uri endpoint, TokenCredential credential, string repository) : this(endpoint, credential, repository, new ContainerRegistryClientOptions()) + { + } + + /// + /// Initializes a new instance of the ContainerRegistryClient for managing container images and artifacts. + /// + /// The URI endpoint of the container registry. This is likely to be similar + /// to "https://{registry-name}.azurecr.io". + /// The API key credential used to authenticate requests + /// against the container registry. + /// + /// Client configuration options for connecting to Azure Container Registry. + /// Thrown when the or is null. + public ContainerRegistryBlobClient(Uri endpoint, TokenCredential credential, string repository, ContainerRegistryClientOptions options) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + Argument.AssertNotNull(credential, nameof(credential)); + Argument.AssertNotNull(options, nameof(options)); + + _endpoint = endpoint; + _registryName = endpoint.Host.Split('.')[0]; + _repositoryName = repository; + _clientDiagnostics = new ClientDiagnostics(options); + + _acrAuthPipeline = HttpPipelineBuilder.Build(options); + _acrAuthClient = new AuthenticationRestClient(_clientDiagnostics, _acrAuthPipeline, endpoint.AbsoluteUri); + + string defaultScope = options.Audience + "/.default"; + _pipeline = HttpPipelineBuilder.Build(options, new ContainerRegistryChallengeAuthenticationPolicy(credential, defaultScope, _acrAuthClient)); + _restClient = new ContainerRegistryRestClient(_clientDiagnostics, _pipeline, _endpoint.AbsoluteUri); + _blobRestClient = new ContainerRegistryBlobRestClient(_clientDiagnostics, _pipeline, _endpoint.AbsoluteUri); + } + + /// Initializes a new instance of RepositoryClient for mocking. + protected ContainerRegistryBlobClient() + { + } + + #region File Upload/Download + + /// + /// + /// + /// + /// + /// + public virtual Response UploadManifest(Stream stream, UploadManifestOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public async virtual Task> UploadManifestAsync(Stream stream, UploadManifestOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new UploadManifestOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(UploadManifest)}"); + scope.Start(); + try + { + string tagOrDigest = options.Tag ?? ContentDescriptor.ComputeDigest(stream); + ResponseWithHeaders response = await _restClient.CreateManifestAsync(_repositoryName, tagOrDigest, stream, options.MediaType.ToString(), cancellationToken).ConfigureAwait(false); + return Response.FromValue(new UploadManifestResult(response.Headers.DockerContentDigest), response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// + /// + /// + /// + /// + public virtual Response UploadBlob(Stream stream, UploadBlobOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public virtual async Task> UploadBlobAsync(Stream stream, UploadBlobOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new UploadBlobOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(UploadBlob)}"); + scope.Start(); + try + { + string digest = ContentDescriptor.ComputeDigest(stream); + + ResponseWithHeaders startUploadResult = + await _blobRestClient.StartUploadAsync(_repositoryName, cancellationToken).ConfigureAwait(false); + + ResponseWithHeaders uploadChunkResult = + await _blobRestClient.UploadChunkAsync(startUploadResult.Headers.Location, stream, cancellationToken).ConfigureAwait(false); + + ResponseWithHeaders completeUploadResult = + await _blobRestClient.CompleteUploadAsync(digest, uploadChunkResult.Headers.Location, null, cancellationToken).ConfigureAwait(false); + + return Response.FromValue(new UploadBlobResult(completeUploadResult.Headers.DockerContentDigest), completeUploadResult.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// + /// + /// + /// + /// + public virtual Response DownloadManifest(string digest, DownloadManifestOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public virtual async Task> DownloadManifestAsync(string digest, DownloadManifestOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new DownloadManifestOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(DownloadManifest)}"); + scope.Start(); + try + { + Response response = await _restClient.GetManifestAsync(_repositoryName, digest, options.MediaType.ToString(), cancellationToken).ConfigureAwait(false); + Response rawResponse = response.GetRawResponse(); + ManifestMediaType mediaType = rawResponse.Headers.ContentType; + + if (!rawResponse.Headers.TryGetValue("Docker-Content-Digest", out string registryDigest)) + { + _clientDiagnostics.CreateRequestFailedException(rawResponse, "Response did not contain \"Docker-Content-Digest\" header."); + } + + if (!ValidateDigest(rawResponse.ContentStream, registryDigest)) + { + _clientDiagnostics.CreateRequestFailedException(rawResponse, "The manifest's digest according to the registry does not match the locally computed digest value."); + } + + return Response.FromValue(new DownloadManifestResult(registryDigest, mediaType, rawResponse.ContentStream, GetArtifactFiles(options.MediaType, response.Value)), rawResponse); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + private static bool ValidateDigest(Stream content, string digest) + { + // Validate that the file content did not change in transmission from the registry. + + // TODO: The registry may use a different digest algorithm - we may need to handle that + string contentDigest = ContentDescriptor.ComputeDigest(content); + content.Position = 0; + return digest.Equals(contentDigest, StringComparison.OrdinalIgnoreCase); + } + + private IReadOnlyList GetArtifactFiles(ManifestMediaType mediaType, ManifestWrapper manifest) + { + List artifactFiles = new List(); + + // TODO: Implement for each of the manifest schemas + if (mediaType == ManifestMediaType.OciManifest) + { + // If has config, add config + if (manifest.Config != null) + { + artifactFiles.Add(new ArtifactBlobProperties(_repositoryName, manifest.Config.Digest, "config.json")); + } + + // Add layers + foreach (var layer in manifest.Layers) + { + artifactFiles.Add(new ArtifactBlobProperties(_repositoryName, layer.Digest)); + } + } + + return artifactFiles; + } + + /// + /// + /// + /// + /// + /// + public virtual Response DownloadBlob(string digest, DownloadBlobOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public virtual async Task> DownloadBlobAsync(string digest, DownloadBlobOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new DownloadBlobOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(DownloadBlob)}"); + scope.Start(); + try + { + ResponseWithHeaders blobResult = await _blobRestClient.GetBlobAsync(_repositoryName, digest, cancellationToken).ConfigureAwait(false); + + if (!ValidateDigest(blobResult.Value, blobResult.Headers.DockerContentDigest)) + { + _clientDiagnostics.CreateRequestFailedException(blobResult.GetRawResponse(), "The manifest's digest according to the registry does not match the locally computed digest value."); + } + + return Response.FromValue(new DownloadBlobResult(digest, blobResult.Value), blobResult.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// + /// + /// + /// + /// + public virtual Response DeleteBlob(string digest, DeleteBlobOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public virtual async Task DeleteBlobAsync(string digest, DeleteBlobOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new DeleteBlobOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(DeleteBlob)}"); + scope.Start(); + try + { + ResponseWithHeaders blobResult = await _blobRestClient.DeleteBlobAsync(_repositoryName, digest, cancellationToken).ConfigureAwait(false); + return blobResult.GetRawResponse(); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// + /// + /// + /// + /// + public virtual Response DeleteManifest(string digest, DeleteManifestOptions options = default, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public virtual async Task DeleteManifestAsync(string digest, DeleteManifestOptions options = default, CancellationToken cancellationToken = default) + { + options ??= new DeleteManifestOptions(); + + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRegistryBlobClient)}.{nameof(DeleteManifest)}"); + scope.Start(); + try + { + return await _restClient.DeleteManifestAsync(_repositoryName, digest, cancellationToken).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + #endregion + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContentDescriptor.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContentDescriptor.cs new file mode 100644 index 000000000000..4450b2865e79 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ContentDescriptor.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Azure.Core; +using System.Security.Cryptography; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + [CodeGenModel("Descriptor")] + internal partial class ContentDescriptor + { + public ContentDescriptor(string mediaType) + { + MediaType = mediaType; + + // TODO: Set Size and Digest from MediaType + // TODO: what if Size passed is null? + // TODO: See https://github.com/sajayantony/acr-cli/blob/main/Services/ContentStore.cs#L134 for details + } + + /// Layer media type. + public string MediaType { get; set; } + /// Layer size. + public long? Size { get; set; } + /// Layer digest. + public string Digest { get; set; } + + /// Specifies a list of URIs from which this object may be downloaded. + public IList Urls { get; } + + /// Additional information provided through arbitrary metadata. + public OciManifestAnnotations Annotations { get; } + + public Stream ToStream() + { + throw new NotImplementedException(); + } + + public static string ComputeDigest(Stream stream) + { + // TODO: cache and dispose SHA256? + using (SHA256 sha256 = SHA256.Create()) + { + // Compute and print the hash values for each file in directory. + try + { + var position = stream.Position; + stream.Position = 0; + var hashValue = sha256.ComputeHash(stream); + stream.Position = position; + return "sha256:" + PrintByteArray(hashValue); + } + catch (IOException e) + { + Console.WriteLine($"I/O Exception: {e.Message}"); + throw; + } + catch (UnauthorizedAccessException e) + { + Console.WriteLine($"Access Exception: {e.Message}"); + throw; + } + } + } + + // Display the byte array in a readable format. + private static string PrintByteArray(byte[] array) + { + var builder = new StringBuilder(); + for (int i = 0; i < array.Length; i++) + { +#pragma warning disable CA1305 // Specify IFormatProvider + builder.AppendFormat($"{array[i]:X2}"); +#pragma warning restore CA1305 // Specify IFormatProvider + //if ((i % 4) == 3) + // builder.AppendFormat(" "); + } +#pragma warning disable CA1304 // Specify CultureInfo + return builder.ToString().ToLower(); +#pragma warning restore CA1304 // Specify CultureInfo + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteBlobOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteBlobOptions.cs new file mode 100644 index 000000000000..ad4709803267 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteBlobOptions.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DeleteBlobOptions + { + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteManifestOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteManifestOptions.cs new file mode 100644 index 000000000000..671a39f10264 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DeleteManifestOptions.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DeleteManifestOptions + { + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobOptions.cs new file mode 100644 index 000000000000..0e28de01fea5 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobOptions.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DownloadBlobOptions + { + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobResult.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobResult.cs new file mode 100644 index 000000000000..c7ba500dce68 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadBlobResult.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.IO; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DownloadBlobResult + { + /// + /// + /// + /// + public DownloadBlobResult(string digest, Stream content) + { + Digest = digest; + Content = content; + } + + /// + /// + public string Digest { get; } + + /// + /// + public Stream Content { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestOptions.cs new file mode 100644 index 000000000000..4b251de5efef --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestOptions.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DownloadManifestOptions + { + /// + /// + public ManifestMediaType MediaType { get; set; } = ManifestMediaType.OciManifest; + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestResult.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestResult.cs new file mode 100644 index 000000000000..22ce08ab9cca --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/DownloadManifestResult.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.IO; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class DownloadManifestResult + { + internal DownloadManifestResult(string digest, ManifestMediaType mediaType, Stream content, IReadOnlyList artifactFiles) + { + Content = content; + MediaType = mediaType; + Digest = digest; + ArtifactFiles = artifactFiles; + } + + /// + /// + public string Digest { get; } + + /// + /// + public ManifestMediaType MediaType { get; } + + /// + /// + public Stream Content { get; } + + /// + /// + public IReadOnlyList ArtifactFiles { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ManifestMediaType.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ManifestMediaType.cs new file mode 100644 index 000000000000..c279acc6f428 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/ManifestMediaType.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public readonly struct ManifestMediaType : IEquatable + { + /// + /// + public static readonly ManifestMediaType OciManifest = new ManifestMediaType("application/vnd.oci.image.manifest.v1+json"); + //public static readonly ManifestMediaType OciIndex = new ManifestMediaType("application/vnd.oci.image.index.v1+json"); + //public static readonly ManifestMediaType DockerManifestV1 = new ManifestMediaType("application/vnd.docker.container.image.v1+json"); + //public static readonly ManifestMediaType DockerManifestV2 = new ManifestMediaType("application/vnd.docker.distribution.manifest.v2+json"); + //public static readonly ManifestMediaType DockerManifestList = new ManifestMediaType("application/vnd.docker.distribution.manifest.list.v2+json"); + + private readonly string _value; + + private ManifestMediaType(string mediaType) + { + _value = mediaType; + } + + /// + /// + /// + public static implicit operator ManifestMediaType(string mediaType) => new ManifestMediaType(mediaType); + + /// + /// + /// + public static explicit operator string(ManifestMediaType mediaType) => mediaType._value; + + /// + /// + /// + /// + /// + public static bool operator ==(ManifestMediaType left, ManifestMediaType right) => Equals(left, right); + + /// + /// + /// + /// + /// + public static bool operator !=(ManifestMediaType left, ManifestMediaType right) => !Equals(left, right); + + /// + /// + /// + /// + public bool Equals(ManifestMediaType other) => _value == other._value; + + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is ManifestMediaType mediaType && Equals(mediaType); + + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value.GetHashCode(); + + /// + /// + /// + public override string ToString() => _value; + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifest.cs new file mode 100644 index 000000000000..cd9335ea466a --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifest.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + [CodeGenModel("OCIManifest")] + internal partial class OciManifest + { + /// V2 image config descriptor. + [CodeGenMember("Config")] + public ContentDescriptor ConfigDescriptor { get; set; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifestAnnotations.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifestAnnotations.cs new file mode 100644 index 000000000000..75c5df3a6997 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/OciManifestAnnotations.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + [CodeGenModel("Annotations")] + internal partial class OciManifestAnnotations + { + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobOptions.cs new file mode 100644 index 000000000000..383e4fcc3038 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobOptions.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class UploadBlobOptions + { + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobResult.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobResult.cs new file mode 100644 index 000000000000..de92fbd68dc3 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadBlobResult.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class UploadBlobResult + { + internal UploadBlobResult(string digest) + { + Digest = digest; + } + + /// + /// + public string Digest { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestOptions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestOptions.cs new file mode 100644 index 000000000000..ab57779b0d09 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestOptions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class UploadManifestOptions + { + /// + /// A tag to assign to the artifact represented by this manifest. + /// + public string Tag { get; set; } + + /// + /// + public ManifestMediaType MediaType { get; set; } = ManifestMediaType.OciManifest; + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestResult.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestResult.cs new file mode 100644 index 000000000000..97a2ad07549d --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Blob/UploadManifestResult.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// + /// + public class UploadManifestResult + { + internal UploadManifestResult(string digest) + { + Digest = digest; + } + + /// + /// + public string Digest { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/ContainerRegistryClient.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/ContainerRegistryClient.cs index 163249eb313e..22aa3bf84e72 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/ContainerRegistryClient.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/ContainerRegistryClient.cs @@ -19,6 +19,7 @@ public partial class ContainerRegistryClient private readonly ClientDiagnostics _clientDiagnostics; private readonly ContainerRegistryRestClient _restClient; private readonly AuthenticationRestClient _acrAuthClient; + private readonly ContainerRegistryBlobRestClient _blobRestClient; /// /// Initializes a new instance of the for managing container images and artifacts, @@ -87,6 +88,7 @@ public ContainerRegistryClient(Uri endpoint, TokenCredential credential, Contain string defaultScope = options.Audience + "/.default"; _pipeline = HttpPipelineBuilder.Build(options, new ContainerRegistryChallengeAuthenticationPolicy(credential, defaultScope, _acrAuthClient)); _restClient = new ContainerRegistryRestClient(_clientDiagnostics, _pipeline, _endpoint.AbsoluteUri); + _blobRestClient = new ContainerRegistryBlobRestClient(_clientDiagnostics, _pipeline, _endpoint.AbsoluteUri); } /// Initializes a new instance of RepositoryClient for mocking. @@ -256,7 +258,8 @@ public virtual ContainerRepository GetRepository(string repositoryName) _endpoint, repositoryName, _clientDiagnostics, - _restClient); + _restClient, + _blobRestClient); } /// @@ -279,7 +282,8 @@ public virtual RegistryArtifact GetArtifact(string repositoryName, string tagOrD repositoryName, tagOrDigest, _clientDiagnostics, - _restClient); + _restClient, + _blobRestClient); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryBlobRestClient.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryBlobRestClient.cs index bf73db2dfbf7..826327cb8837 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryBlobRestClient.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryBlobRestClient.cs @@ -350,7 +350,7 @@ public ResponseWithHeaders MountBlob(stri } } - internal HttpMessage CreateGetUploadStatusRequest(string location) + internal HttpMessage CreateGetUploadStatusRequest(string nextLink) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -358,24 +358,24 @@ internal HttpMessage CreateGetUploadStatusRequest(string location) var uri = new RawRequestUriBuilder(); uri.AppendRaw(url, false); uri.AppendPath("/", false); - uri.AppendPath(location, false); + uri.AppendRawNextLink(nextLink, false); request.Uri = uri; request.Headers.Add("Accept", "application/json"); return message; } /// Retrieve status of upload identified by uuid. The primary purpose of this endpoint is to resolve the current status of a resumable upload. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// The cancellation token to use. - /// is null. - public async Task> GetUploadStatusAsync(string location, CancellationToken cancellationToken = default) + /// is null. + public async Task> GetUploadStatusAsync(string nextLink, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateGetUploadStatusRequest(location); + using var message = CreateGetUploadStatusRequest(nextLink); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ContainerRegistryBlobGetUploadStatusHeaders(message.Response); switch (message.Response.Status) @@ -388,17 +388,17 @@ public async Task Retrieve status of upload identified by uuid. The primary purpose of this endpoint is to resolve the current status of a resumable upload. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// The cancellation token to use. - /// is null. - public ResponseWithHeaders GetUploadStatus(string location, CancellationToken cancellationToken = default) + /// is null. + public ResponseWithHeaders GetUploadStatus(string nextLink, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateGetUploadStatusRequest(location); + using var message = CreateGetUploadStatusRequest(nextLink); _pipeline.Send(message, cancellationToken); var headers = new ContainerRegistryBlobGetUploadStatusHeaders(message.Response); switch (message.Response.Status) @@ -410,7 +410,7 @@ public ResponseWithHeaders GetUploa } } - internal HttpMessage CreateUploadChunkRequest(string location, Stream value) + internal HttpMessage CreateUploadChunkRequest(string nextLink, Stream value) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -418,7 +418,7 @@ internal HttpMessage CreateUploadChunkRequest(string location, Stream value) var uri = new RawRequestUriBuilder(); uri.AppendRaw(url, false); uri.AppendPath("/", false); - uri.AppendPath(location, false); + uri.AppendRawNextLink(nextLink, false); request.Uri = uri; request.Headers.Add("Accept", "application/json"); request.Headers.Add("Content-Type", "application/octet-stream"); @@ -427,22 +427,22 @@ internal HttpMessage CreateUploadChunkRequest(string location, Stream value) } /// Upload a stream of data without completing the upload. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// Raw data of blob. /// The cancellation token to use. - /// or is null. - public async Task> UploadChunkAsync(string location, Stream value, CancellationToken cancellationToken = default) + /// or is null. + public async Task> UploadChunkAsync(string nextLink, Stream value, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } - using var message = CreateUploadChunkRequest(location, value); + using var message = CreateUploadChunkRequest(nextLink, value); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ContainerRegistryBlobUploadChunkHeaders(message.Response); switch (message.Response.Status) @@ -455,22 +455,22 @@ public async Task> } /// Upload a stream of data without completing the upload. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// Raw data of blob. /// The cancellation token to use. - /// or is null. - public ResponseWithHeaders UploadChunk(string location, Stream value, CancellationToken cancellationToken = default) + /// or is null. + public ResponseWithHeaders UploadChunk(string nextLink, Stream value, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } - using var message = CreateUploadChunkRequest(location, value); + using var message = CreateUploadChunkRequest(nextLink, value); _pipeline.Send(message, cancellationToken); var headers = new ContainerRegistryBlobUploadChunkHeaders(message.Response); switch (message.Response.Status) @@ -482,7 +482,7 @@ public ResponseWithHeaders UploadChunk( } } - internal HttpMessage CreateCompleteUploadRequest(string digest, string location, Stream value) + internal HttpMessage CreateCompleteUploadRequest(string digest, string nextLink, Stream value) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -490,7 +490,7 @@ internal HttpMessage CreateCompleteUploadRequest(string digest, string location, var uri = new RawRequestUriBuilder(); uri.AppendRaw(url, false); uri.AppendPath("/", false); - uri.AppendPath(location, false); + uri.AppendRawNextLink(nextLink, false); uri.AppendQuery("digest", digest, true); request.Uri = uri; request.Headers.Add("Accept", "application/json"); @@ -504,22 +504,22 @@ internal HttpMessage CreateCompleteUploadRequest(string digest, string location, /// Complete the upload, providing all the data in the body, if necessary. A request without a body will just complete the upload with previously uploaded content. /// Digest of a BLOB. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// Optional raw data of blob. /// The cancellation token to use. - /// or is null. - public async Task> CompleteUploadAsync(string digest, string location, Stream value = null, CancellationToken cancellationToken = default) + /// or is null. + public async Task> CompleteUploadAsync(string digest, string nextLink, Stream value = null, CancellationToken cancellationToken = default) { if (digest == null) { throw new ArgumentNullException(nameof(digest)); } - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateCompleteUploadRequest(digest, location, value); + using var message = CreateCompleteUploadRequest(digest, nextLink, value); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ContainerRegistryBlobCompleteUploadHeaders(message.Response); switch (message.Response.Status) @@ -533,22 +533,22 @@ public async Task Complete the upload, providing all the data in the body, if necessary. A request without a body will just complete the upload with previously uploaded content. /// Digest of a BLOB. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// Optional raw data of blob. /// The cancellation token to use. - /// or is null. - public ResponseWithHeaders CompleteUpload(string digest, string location, Stream value = null, CancellationToken cancellationToken = default) + /// or is null. + public ResponseWithHeaders CompleteUpload(string digest, string nextLink, Stream value = null, CancellationToken cancellationToken = default) { if (digest == null) { throw new ArgumentNullException(nameof(digest)); } - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateCompleteUploadRequest(digest, location, value); + using var message = CreateCompleteUploadRequest(digest, nextLink, value); _pipeline.Send(message, cancellationToken); var headers = new ContainerRegistryBlobCompleteUploadHeaders(message.Response); switch (message.Response.Status) @@ -560,7 +560,7 @@ public ResponseWithHeaders CompleteU } } - internal HttpMessage CreateCancelUploadRequest(string location) + internal HttpMessage CreateCancelUploadRequest(string nextLink) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -568,24 +568,24 @@ internal HttpMessage CreateCancelUploadRequest(string location) var uri = new RawRequestUriBuilder(); uri.AppendRaw(url, false); uri.AppendPath("/", false); - uri.AppendPath(location, false); + uri.AppendRawNextLink(nextLink, false); request.Uri = uri; request.Headers.Add("Accept", "application/json"); return message; } /// Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// The cancellation token to use. - /// is null. - public async Task CancelUploadAsync(string location, CancellationToken cancellationToken = default) + /// is null. + public async Task CancelUploadAsync(string nextLink, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateCancelUploadRequest(location); + using var message = CreateCancelUploadRequest(nextLink); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); switch (message.Response.Status) { @@ -597,17 +597,17 @@ public async Task CancelUploadAsync(string location, CancellationToken } /// Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout. - /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). + /// Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) ). /// The cancellation token to use. - /// is null. - public Response CancelUpload(string location, CancellationToken cancellationToken = default) + /// is null. + public Response CancelUpload(string nextLink, CancellationToken cancellationToken = default) { - if (location == null) + if (nextLink == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(nextLink)); } - using var message = CreateCancelUploadRequest(location); + using var message = CreateCancelUploadRequest(nextLink); _pipeline.Send(message, cancellationToken); switch (message.Response.Status) { diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryModelFactory.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryModelFactory.cs index 98db20ed7d9c..bf0afc1b96a8 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryModelFactory.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryModelFactory.cs @@ -13,7 +13,7 @@ namespace Azure.Containers.ContainerRegistry public static partial class ContainerRegistryModelFactory { /// Initializes a new instance of ContainerRepositoryProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Image created time. /// Image last update time. @@ -31,7 +31,7 @@ public static ContainerRepositoryProperties ContainerRepositoryProperties(string } /// Initializes a new instance of ArtifactTagProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Tag name. /// Tag digest. diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryRestClient.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryRestClient.cs index e63ccb5c40f9..f5f5759680f9 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryRestClient.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/ContainerRegistryRestClient.cs @@ -6,6 +6,7 @@ #nullable disable using System; +using System.IO; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -162,7 +163,7 @@ public Response GetManifest(string name, string reference, stri } } - internal HttpMessage CreateCreateManifestRequest(string name, string reference, Manifest payload) + internal HttpMessage CreateCreateManifestRequest(string name, string reference, Stream payload, string contentType) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -175,10 +176,11 @@ internal HttpMessage CreateCreateManifestRequest(string name, string reference, uri.AppendPath(reference, true); request.Uri = uri; request.Headers.Add("Accept", "application/json"); - request.Headers.Add("Content-Type", "application/vnd.docker.distribution.manifest.v2+json"); - var content = new Utf8JsonRequestContent(); - content.JsonWriter.WriteObjectValue(payload); - request.Content = content; + if (contentType != null) + { + request.Headers.Add("Content-Type", contentType); + } + request.Content = RequestContent.Create(payload); return message; } @@ -186,9 +188,10 @@ internal HttpMessage CreateCreateManifestRequest(string name, string reference, /// Name of the image (including the namespace). /// A tag or a digest, pointing to a specific image. /// Manifest body, can take v1 or v2 values depending on accept header. + /// The manifest's Content-Type. /// The cancellation token to use. /// , , or is null. - public async Task> CreateManifestAsync(string name, string reference, Manifest payload, CancellationToken cancellationToken = default) + public async Task> CreateManifestAsync(string name, string reference, Stream payload, string contentType = null, CancellationToken cancellationToken = default) { if (name == null) { @@ -203,18 +206,13 @@ public async Task Name of the image (including the namespace). /// A tag or a digest, pointing to a specific image. /// Manifest body, can take v1 or v2 values depending on accept header. + /// The manifest's Content-Type. /// The cancellation token to use. /// , , or is null. - public ResponseWithHeaders CreateManifest(string name, string reference, Manifest payload, CancellationToken cancellationToken = default) + public ResponseWithHeaders CreateManifest(string name, string reference, Stream payload, string contentType = null, CancellationToken cancellationToken = default) { if (name == null) { @@ -241,18 +240,13 @@ public ResponseWithHeaders Creat throw new ArgumentNullException(nameof(payload)); } - using var message = CreateCreateManifestRequest(name, reference, payload); + using var message = CreateCreateManifestRequest(name, reference, payload, contentType); _pipeline.Send(message, cancellationToken); var headers = new ContainerRegistryCreateManifestHeaders(message.Response); switch (message.Response.Status) { case 201: - { - object value = default; - using var document = JsonDocument.Parse(message.Response.ContentStream); - value = document.RootElement.GetObject(); - return ResponseWithHeaders.FromValue(value, headers, message.Response); - } + return ResponseWithHeaders.FromValue(headers, message.Response); default: throw _clientDiagnostics.CreateRequestFailedException(message.Response); } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/AcrManifests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/AcrManifests.cs index 80f367377fee..a49829bdc334 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/AcrManifests.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/AcrManifests.cs @@ -20,7 +20,7 @@ internal AcrManifests() } /// Initializes a new instance of AcrManifests. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// List of manifests. /// @@ -32,7 +32,7 @@ internal AcrManifests(string registryLoginServer, string repository, IReadOnlyLi Link = link; } - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. public string RegistryLoginServer { get; } /// Image name. public string Repository { get; } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactArchitecture.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactArchitecture.cs index ecc6bd186998..5a4ec3a47574 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactArchitecture.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactArchitecture.cs @@ -10,7 +10,7 @@ namespace Azure.Containers.ContainerRegistry { - /// The artifact platform's architecture. + /// The ArtifactArchitecture. public readonly partial struct ArtifactArchitecture : IEquatable { private readonly string _value; @@ -36,31 +36,31 @@ public ArtifactArchitecture(string value) private const string S390XValue = "s390x"; private const string WasmValue = "wasm"; - /// i386. + /// 386. public static ArtifactArchitecture I386 { get; } = new ArtifactArchitecture(I386Value); - /// AMD64. + /// amd64. public static ArtifactArchitecture Amd64 { get; } = new ArtifactArchitecture(Amd64Value); - /// ARM. + /// arm. public static ArtifactArchitecture Arm { get; } = new ArtifactArchitecture(ArmValue); - /// ARM64. + /// arm64. public static ArtifactArchitecture Arm64 { get; } = new ArtifactArchitecture(Arm64Value); - /// MIPS. + /// mips. public static ArtifactArchitecture Mips { get; } = new ArtifactArchitecture(MipsValue); - /// MIPSLE. + /// mipsle. public static ArtifactArchitecture MipsLe { get; } = new ArtifactArchitecture(MipsLeValue); - /// MIPS64. + /// mips64. public static ArtifactArchitecture Mips64 { get; } = new ArtifactArchitecture(Mips64Value); - /// MIPS64LE. + /// mips64le. public static ArtifactArchitecture Mips64Le { get; } = new ArtifactArchitecture(Mips64LeValue); - /// PPC64. + /// ppc64. public static ArtifactArchitecture Ppc64 { get; } = new ArtifactArchitecture(Ppc64Value); - /// PPC64LE. + /// ppc64le. public static ArtifactArchitecture Ppc64Le { get; } = new ArtifactArchitecture(Ppc64LeValue); - /// RISCv64. + /// riscv64. public static ArtifactArchitecture RiscV64 { get; } = new ArtifactArchitecture(RiscV64Value); /// s390x. public static ArtifactArchitecture S390X { get; } = new ArtifactArchitecture(S390XValue); - /// Wasm. + /// wasm. public static ArtifactArchitecture Wasm { get; } = new ArtifactArchitecture(WasmValue); /// Determines if two values are the same. public static bool operator ==(ArtifactArchitecture left, ArtifactArchitecture right) => left.Equals(right); diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.Serialization.cs new file mode 100644 index 000000000000..b8f3917a50c1 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.Serialization.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Containers.ContainerRegistry; +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + internal partial class ArtifactManifest + { + internal static ArtifactManifest DeserializeArtifactManifest(JsonElement element) + { + if (element.TryGetProperty("mediaType", out JsonElement discriminator)) + { + switch (discriminator.GetString()) + { + case "ManifestWrapper": return ManifestWrapper.DeserializeManifestWrapper(element); + case "application/vnd.docker.distribution.manifest.list.v2+json": return ManifestList.DeserializeManifestList(element); + case "application/vnd.docker.distribution.manifest.v1+json": return V1Manifest.DeserializeV1Manifest(element); + case "application/vnd.docker.distribution.manifest.v2+json": return V2Manifest.DeserializeV2Manifest(element); + case "application/vnd.oci.image.index.v1+json": return OCIIndex.DeserializeOCIIndex(element); + case "application/vnd.oci.image.manifest.v1+json": return OciManifest.DeserializeOciManifest(element); + } + } + int schemaVersion = default; + string mediaType = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("schemaVersion")) + { + schemaVersion = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } + } + return new ArtifactManifest(schemaVersion, mediaType); + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.cs new file mode 100644 index 000000000000..95ce4f7e6bdf --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifest.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// Returns the requested manifest file. + internal partial class ArtifactManifest + { + /// Initializes a new instance of ArtifactManifest. + /// Schema version. + internal ArtifactManifest(int schemaVersion) + { + SchemaVersion = schemaVersion; + } + + /// Initializes a new instance of ArtifactManifest. + /// Schema version. + /// Media type for this Manifest. + internal ArtifactManifest(int schemaVersion, string mediaType) + { + SchemaVersion = schemaVersion; + MediaType = mediaType; + } + + /// Schema version. + public int SchemaVersion { get; } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestPlatform.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestPlatform.cs index 52d1f5e70fda..445f21db8839 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestPlatform.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestPlatform.cs @@ -9,7 +9,7 @@ namespace Azure.Containers.ContainerRegistry { - /// The artifact's platform, consisting of operating system and architecture. + /// Manifest attributes details. public partial class ArtifactManifestPlatform { /// Initializes a new instance of ArtifactManifestPlatform. diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.Serialization.cs index 6710d496e91b..a2926ae6eba4 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.Serialization.cs @@ -24,6 +24,7 @@ internal static ArtifactManifestProperties DeserializeArtifactManifestProperties DateTimeOffset lastUpdateTime = default; Optional architecture = default; Optional os = default; + Optional mediaType = default; Optional> references = default; Optional> tags = default; Optional deleteEnabled = default; @@ -98,6 +99,11 @@ internal static ArtifactManifestProperties DeserializeArtifactManifestProperties os = new ArtifactOperatingSystem(property0.Value.GetString()); continue; } + if (property0.NameEquals("mediaType")) + { + mediaType = property0.Value.GetString(); + continue; + } if (property0.NameEquals("references")) { if (property0.Value.ValueKind == JsonValueKind.Null) @@ -194,7 +200,7 @@ internal static ArtifactManifestProperties DeserializeArtifactManifestProperties continue; } } - return new ArtifactManifestProperties(registry.Value, imageName.Value, digest, Optional.ToNullable(imageSize), createdTime, lastUpdateTime, Optional.ToNullable(architecture), Optional.ToNullable(os), Optional.ToList(references), Optional.ToList(tags), Optional.ToNullable(deleteEnabled), Optional.ToNullable(writeEnabled), Optional.ToNullable(listEnabled), Optional.ToNullable(readEnabled), quarantineState.Value, quarantineDetails.Value); + return new ArtifactManifestProperties(registry.Value, imageName.Value, digest, Optional.ToNullable(imageSize), createdTime, lastUpdateTime, Optional.ToNullable(architecture), Optional.ToNullable(os), mediaType.Value, Optional.ToList(references), Optional.ToList(tags), Optional.ToNullable(deleteEnabled), Optional.ToNullable(writeEnabled), Optional.ToNullable(listEnabled), Optional.ToNullable(readEnabled), quarantineState.Value, quarantineDetails.Value); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.cs index b730545d6625..ffbab0e48ed4 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactManifestProperties.cs @@ -34,7 +34,7 @@ internal ArtifactManifestProperties(string digest, DateTimeOffset createdOn, Dat } /// Initializes a new instance of ArtifactManifestProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Repository name. /// Manifest. /// Image size. @@ -42,6 +42,7 @@ internal ArtifactManifestProperties(string digest, DateTimeOffset createdOn, Dat /// Last update time. /// CPU architecture. /// Operating system. + /// Media type. /// List of artifacts that are referenced by this manifest list, with information about the platform each supports. This list will be empty if this is a leaf manifest and not a manifest list. /// List of tags. /// Delete enabled. @@ -50,7 +51,7 @@ internal ArtifactManifestProperties(string digest, DateTimeOffset createdOn, Dat /// Read enabled. /// Quarantine state. /// Quarantine details. - internal ArtifactManifestProperties(string registryLoginServer, string repositoryName, string digest, long? size, DateTimeOffset createdOn, DateTimeOffset lastUpdatedOn, ArtifactArchitecture? architecture, ArtifactOperatingSystem? operatingSystem, IReadOnlyList relatedArtifacts, IReadOnlyList tags, bool? canDelete, bool? canWrite, bool? canList, bool? canRead, string quarantineState, string quarantineDetails) + internal ArtifactManifestProperties(string registryLoginServer, string repositoryName, string digest, long? size, DateTimeOffset createdOn, DateTimeOffset lastUpdatedOn, ArtifactArchitecture? architecture, ArtifactOperatingSystem? operatingSystem, string mediaType, IReadOnlyList relatedArtifacts, IReadOnlyList tags, bool? canDelete, bool? canWrite, bool? canList, bool? canRead, string quarantineState, string quarantineDetails) { RegistryLoginServer = registryLoginServer; RepositoryName = repositoryName; @@ -60,6 +61,7 @@ internal ArtifactManifestProperties(string registryLoginServer, string repositor LastUpdatedOn = lastUpdatedOn; Architecture = architecture; OperatingSystem = operatingSystem; + MediaType = mediaType; RelatedArtifacts = relatedArtifacts; Tags = tags; CanDelete = canDelete; @@ -70,7 +72,7 @@ internal ArtifactManifestProperties(string registryLoginServer, string repositor QuarantineDetails = quarantineDetails; } - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. public string RegistryLoginServer { get; } /// Repository name. public string RepositoryName { get; } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagOrderBy.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagOrderBy.cs index 3f4d1b9278b3..3ae87cd04516 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagOrderBy.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagOrderBy.cs @@ -7,7 +7,7 @@ namespace Azure.Containers.ContainerRegistry { - /// Sort options for ordering tags in a collection. + /// The ArtifactTagOrderBy. public enum ArtifactTagOrderBy { /// Do not provide an orderby value in the request. diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagProperties.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagProperties.cs index f66f5c67753c..58a4a629d39b 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagProperties.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ArtifactTagProperties.cs @@ -13,7 +13,7 @@ namespace Azure.Containers.ContainerRegistry public partial class ArtifactTagProperties { /// Initializes a new instance of ArtifactTagProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Tag name. /// Tag digest. @@ -48,7 +48,7 @@ internal ArtifactTagProperties(string registryLoginServer, string repositoryName } /// Initializes a new instance of ArtifactTagProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Tag name. /// Tag digest. @@ -72,7 +72,7 @@ internal ArtifactTagProperties(string registryLoginServer, string repositoryName CanRead = canRead; } - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. public string RegistryLoginServer { get; } /// Image name. public string RepositoryName { get; } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContainerRepositoryProperties.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContainerRepositoryProperties.cs index b19a728fcb1b..64118a45dc38 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContainerRepositoryProperties.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContainerRepositoryProperties.cs @@ -13,7 +13,7 @@ namespace Azure.Containers.ContainerRegistry public partial class ContainerRepositoryProperties { /// Initializes a new instance of ContainerRepositoryProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Image created time. /// Image last update time. @@ -40,7 +40,7 @@ internal ContainerRepositoryProperties(string registryLoginServer, string name, } /// Initializes a new instance of ContainerRepositoryProperties. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// Image created time. /// Image last update time. @@ -66,7 +66,7 @@ internal ContainerRepositoryProperties(string registryLoginServer, string name, TeleportEnabled = teleportEnabled; } - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. public string RegistryLoginServer { get; } /// Image name. public string Name { get; } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.Serialization.cs new file mode 100644 index 000000000000..a5bfcc654a9f --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.Serialization.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + internal partial class ContentDescriptor + { + internal static ContentDescriptor DeserializeContentDescriptor(JsonElement element) + { + Optional mediaType = default; + Optional size = default; + Optional digest = default; + Optional> urls = default; + Optional annotations = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } + if (property.NameEquals("size")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + property.ThrowNonNullablePropertyIsNull(); + continue; + } + size = property.Value.GetInt64(); + continue; + } + if (property.NameEquals("digest")) + { + digest = property.Value.GetString(); + continue; + } + if (property.NameEquals("urls")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + property.ThrowNonNullablePropertyIsNull(); + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + array.Add(new Uri(item.GetString())); + } + urls = array; + continue; + } + if (property.NameEquals("annotations")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + annotations = null; + continue; + } + annotations = OciManifestAnnotations.DeserializeOciManifestAnnotations(property.Value); + continue; + } + } + return new ContentDescriptor(mediaType.Value, Optional.ToNullable(size), digest.Value, Optional.ToList(urls), annotations.Value); + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.cs new file mode 100644 index 000000000000..eb8f607e4467 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ContentDescriptor.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using Azure.Core; + +namespace Azure.Containers.ContainerRegistry.Specialized +{ + /// Docker V2 image layer descriptor including config and layers. + internal partial class ContentDescriptor + { + /// Initializes a new instance of ContentDescriptor. + internal ContentDescriptor() + { + Urls = new ChangeTrackingList(); + } + + /// Initializes a new instance of ContentDescriptor. + /// Layer media type. + /// Layer size. + /// Layer digest. + /// Specifies a list of URIs from which this object may be downloaded. + /// Additional information provided through arbitrary metadata. + internal ContentDescriptor(string mediaType, long? size, string digest, IList urls, OciManifestAnnotations annotations) + { + MediaType = mediaType; + Size = size; + Digest = digest; + Urls = urls; + Annotations = annotations; + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.Serialization.cs deleted file mode 100644 index 0b0d7e5c804f..000000000000 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.Serialization.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System.Collections.Generic; -using System.Text.Json; -using Azure.Core; - -namespace Azure.Containers.ContainerRegistry -{ - internal partial class Descriptor : IUtf8JsonSerializable - { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(MediaType)) - { - writer.WritePropertyName("mediaType"); - writer.WriteStringValue(MediaType); - } - if (Optional.IsDefined(Size)) - { - writer.WritePropertyName("size"); - writer.WriteNumberValue(Size.Value); - } - if (Optional.IsDefined(Digest)) - { - writer.WritePropertyName("digest"); - writer.WriteStringValue(Digest); - } - if (Optional.IsCollectionDefined(Urls)) - { - writer.WritePropertyName("urls"); - writer.WriteStartArray(); - foreach (var item in Urls) - { - writer.WriteStringValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Annotations)) - { - if (Annotations != null) - { - writer.WritePropertyName("annotations"); - writer.WriteObjectValue(Annotations); - } - else - { - writer.WriteNull("annotations"); - } - } - writer.WriteEndObject(); - } - - internal static Descriptor DeserializeDescriptor(JsonElement element) - { - Optional mediaType = default; - Optional size = default; - Optional digest = default; - Optional> urls = default; - Optional annotations = default; - foreach (var property in element.EnumerateObject()) - { - if (property.NameEquals("mediaType")) - { - mediaType = property.Value.GetString(); - continue; - } - if (property.NameEquals("size")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } - size = property.Value.GetInt64(); - continue; - } - if (property.NameEquals("digest")) - { - digest = property.Value.GetString(); - continue; - } - if (property.NameEquals("urls")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } - List array = new List(); - foreach (var item in property.Value.EnumerateArray()) - { - array.Add(item.GetString()); - } - urls = array; - continue; - } - if (property.NameEquals("annotations")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - annotations = null; - continue; - } - annotations = Annotations.DeserializeAnnotations(property.Value); - continue; - } - } - return new Descriptor(mediaType.Value, Optional.ToNullable(size), digest.Value, Optional.ToList(urls), annotations.Value); - } - } -} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.cs deleted file mode 100644 index 1034f52083f1..000000000000 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Descriptor.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System.Collections.Generic; -using Azure.Core; - -namespace Azure.Containers.ContainerRegistry -{ - /// Docker V2 image layer descriptor including config and layers. - internal partial class Descriptor - { - /// Initializes a new instance of Descriptor. - public Descriptor() - { - Urls = new ChangeTrackingList(); - } - - /// Initializes a new instance of Descriptor. - /// Layer media type. - /// Layer size. - /// Layer digest. - /// Specifies a list of URIs from which this object may be downloaded. - /// Additional information provided through arbitrary metadata. - internal Descriptor(string mediaType, long? size, string digest, IList urls, Annotations annotations) - { - MediaType = mediaType; - Size = size; - Digest = digest; - Urls = urls; - Annotations = annotations; - } - - /// Layer media type. - public string MediaType { get; set; } - /// Layer size. - public long? Size { get; set; } - /// Layer digest. - public string Digest { get; set; } - /// Specifies a list of URIs from which this object may be downloaded. - public IList Urls { get; } - /// Additional information provided through arbitrary metadata. - public Annotations Annotations { get; set; } - } -} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.Serialization.cs index 605defc93d64..ec323a6e2122 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.Serialization.cs @@ -10,19 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class FsLayer : IUtf8JsonSerializable + internal partial class FsLayer { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(BlobSum)) - { - writer.WritePropertyName("blobSum"); - writer.WriteStringValue(BlobSum); - } - writer.WriteEndObject(); - } - internal static FsLayer DeserializeFsLayer(JsonElement element) { Optional blobSum = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.cs index 4c08cf841bb5..e68a7ce23057 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/FsLayer.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class FsLayer { /// Initializes a new instance of FsLayer. - public FsLayer() + internal FsLayer() { } @@ -23,6 +23,6 @@ internal FsLayer(string blobSum) } /// SHA of an image layer. - public string BlobSum { get; set; } + public string BlobSum { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.Serialization.cs index ca9e7f59a62b..d7e42fc705e1 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.Serialization.cs @@ -10,19 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class History : IUtf8JsonSerializable + internal partial class History { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(V1Compatibility)) - { - writer.WritePropertyName("v1Compatibility"); - writer.WriteStringValue(V1Compatibility); - } - writer.WriteEndObject(); - } - internal static History DeserializeHistory(JsonElement element) { Optional v1Compatibility = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.cs index e8d94d016d96..85dc513a2c83 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/History.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class History { /// Initializes a new instance of History. - public History() + internal History() { } @@ -23,6 +23,6 @@ internal History(string v1Compatibility) } /// The raw v1 compatibility information. - public string V1Compatibility { get; set; } + public string V1Compatibility { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.Serialization.cs index 1a7b236b9605..15b059dd9be0 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.Serialization.cs @@ -10,29 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class ImageSignature : IUtf8JsonSerializable + internal partial class ImageSignature { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Header)) - { - writer.WritePropertyName("header"); - writer.WriteObjectValue(Header); - } - if (Optional.IsDefined(Signature)) - { - writer.WritePropertyName("signature"); - writer.WriteStringValue(Signature); - } - if (Optional.IsDefined(Protected)) - { - writer.WritePropertyName("protected"); - writer.WriteStringValue(Protected); - } - writer.WriteEndObject(); - } - internal static ImageSignature DeserializeImageSignature(JsonElement element) { Optional header = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.cs index 99e76fa286db..923b68e06acf 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ImageSignature.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class ImageSignature { /// Initializes a new instance of ImageSignature. - public ImageSignature() + internal ImageSignature() { } @@ -27,10 +27,10 @@ internal ImageSignature(JWK header, string signature, string @protected) } /// A JSON web signature. - public JWK Header { get; set; } + public JWK Header { get; } /// A signature for the image manifest, signed by a libtrust private key. - public string Signature { get; set; } + public string Signature { get; } /// The signed protected header. - public string Protected { get; set; } + public string Protected { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.Serialization.cs index 907fa42926f2..282c4fb59023 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.Serialization.cs @@ -10,24 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class JWK : IUtf8JsonSerializable + internal partial class JWK { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Jwk)) - { - writer.WritePropertyName("jwk"); - writer.WriteObjectValue(Jwk); - } - if (Optional.IsDefined(Alg)) - { - writer.WritePropertyName("alg"); - writer.WriteStringValue(Alg); - } - writer.WriteEndObject(); - } - internal static JWK DeserializeJWK(JsonElement element) { Optional jwk = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.cs index fc1b294b7bcb..f0b30848f12f 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWK.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class JWK { /// Initializes a new instance of JWK. - public JWK() + internal JWK() { } @@ -25,8 +25,8 @@ internal JWK(JWKHeader jwk, string alg) } /// JSON web key parameter. - public JWKHeader Jwk { get; set; } + public JWKHeader Jwk { get; } /// The algorithm used to sign or encrypt the JWT. - public string Alg { get; set; } + public string Alg { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.Serialization.cs index eb394f39b94d..d10dd9e06fef 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.Serialization.cs @@ -10,39 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class JWKHeader : IUtf8JsonSerializable + internal partial class JWKHeader { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Crv)) - { - writer.WritePropertyName("crv"); - writer.WriteStringValue(Crv); - } - if (Optional.IsDefined(Kid)) - { - writer.WritePropertyName("kid"); - writer.WriteStringValue(Kid); - } - if (Optional.IsDefined(Kty)) - { - writer.WritePropertyName("kty"); - writer.WriteStringValue(Kty); - } - if (Optional.IsDefined(X)) - { - writer.WritePropertyName("x"); - writer.WriteStringValue(X); - } - if (Optional.IsDefined(Y)) - { - writer.WritePropertyName("y"); - writer.WriteStringValue(Y); - } - writer.WriteEndObject(); - } - internal static JWKHeader DeserializeJWKHeader(JsonElement element) { Optional crv = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.cs index 706053f6dd83..8c15893b2315 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/JWKHeader.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class JWKHeader { /// Initializes a new instance of JWKHeader. - public JWKHeader() + internal JWKHeader() { } @@ -31,14 +31,14 @@ internal JWKHeader(string crv, string kid, string kty, string x, string y) } /// crv value. - public string Crv { get; set; } + public string Crv { get; } /// kid value. - public string Kid { get; set; } + public string Kid { get; } /// kty value. - public string Kty { get; set; } + public string Kty { get; } /// x value. - public string X { get; set; } + public string X { get; } /// y value. - public string Y { get; set; } + public string Y { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.Serialization.cs deleted file mode 100644 index 3bb9d1d323f8..000000000000 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.Serialization.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System.Text.Json; -using Azure.Core; - -namespace Azure.Containers.ContainerRegistry -{ - internal partial class Manifest : IUtf8JsonSerializable - { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - - internal static Manifest DeserializeManifest(JsonElement element) - { - Optional schemaVersion = default; - foreach (var property in element.EnumerateObject()) - { - if (property.NameEquals("schemaVersion")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } - schemaVersion = property.Value.GetInt32(); - continue; - } - } - return new Manifest(Optional.ToNullable(schemaVersion)); - } - } -} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.cs deleted file mode 100644 index 99feb03f9afc..000000000000 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Manifest.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -namespace Azure.Containers.ContainerRegistry -{ - /// Returns the requested manifest file. - internal partial class Manifest - { - /// Initializes a new instance of Manifest. - public Manifest() - { - } - - /// Initializes a new instance of Manifest. - /// Schema version. - internal Manifest(int? schemaVersion) - { - SchemaVersion = schemaVersion; - } - - /// Schema version. - public int? SchemaVersion { get; set; } - } -} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.Serialization.cs index 53676ba0ba50..c39ddf3ed3d4 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.Serialization.cs @@ -22,6 +22,7 @@ internal static ManifestAttributesBase DeserializeManifestAttributesBase(JsonEle DateTimeOffset lastUpdateTime = default; Optional architecture = default; Optional os = default; + Optional mediaType = default; Optional> references = default; Optional> tags = default; Optional deleteEnabled = default; @@ -77,6 +78,11 @@ internal static ManifestAttributesBase DeserializeManifestAttributesBase(JsonEle os = new ArtifactOperatingSystem(property.Value.GetString()); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } if (property.NameEquals("references")) { if (property.Value.ValueKind == JsonValueKind.Null) @@ -170,7 +176,7 @@ internal static ManifestAttributesBase DeserializeManifestAttributesBase(JsonEle continue; } } - return new ManifestAttributesBase(digest, Optional.ToNullable(imageSize), createdTime, lastUpdateTime, Optional.ToNullable(architecture), Optional.ToNullable(os), Optional.ToList(references), Optional.ToList(tags), Optional.ToNullable(deleteEnabled), Optional.ToNullable(writeEnabled), Optional.ToNullable(listEnabled), Optional.ToNullable(readEnabled), quarantineState.Value, quarantineDetails.Value); + return new ManifestAttributesBase(digest, Optional.ToNullable(imageSize), createdTime, lastUpdateTime, Optional.ToNullable(architecture), Optional.ToNullable(os), mediaType.Value, Optional.ToList(references), Optional.ToList(tags), Optional.ToNullable(deleteEnabled), Optional.ToNullable(writeEnabled), Optional.ToNullable(listEnabled), Optional.ToNullable(readEnabled), quarantineState.Value, quarantineDetails.Value); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.cs index 69955dcece6a..f9367520df11 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestAttributesBase.cs @@ -40,6 +40,7 @@ internal ManifestAttributesBase(string digest, DateTimeOffset createdOn, DateTim /// Last update time. /// CPU architecture. /// Operating system. + /// Media type. /// List of artifacts that are referenced by this manifest list, with information about the platform each supports. This list will be empty if this is a leaf manifest and not a manifest list. /// List of tags. /// Delete enabled. @@ -48,7 +49,7 @@ internal ManifestAttributesBase(string digest, DateTimeOffset createdOn, DateTim /// Read enabled. /// Quarantine state. /// Quarantine details. - internal ManifestAttributesBase(string digest, long? size, DateTimeOffset createdOn, DateTimeOffset lastUpdatedOn, ArtifactArchitecture? architecture, ArtifactOperatingSystem? operatingSystem, IReadOnlyList relatedArtifacts, IReadOnlyList tags, bool? canDelete, bool? canWrite, bool? canList, bool? canRead, string quarantineState, string quarantineDetails) + internal ManifestAttributesBase(string digest, long? size, DateTimeOffset createdOn, DateTimeOffset lastUpdatedOn, ArtifactArchitecture? architecture, ArtifactOperatingSystem? operatingSystem, string mediaType, IReadOnlyList relatedArtifacts, IReadOnlyList tags, bool? canDelete, bool? canWrite, bool? canList, bool? canRead, string quarantineState, string quarantineDetails) { Digest = digest; Size = size; @@ -56,6 +57,7 @@ internal ManifestAttributesBase(string digest, long? size, DateTimeOffset create LastUpdatedOn = lastUpdatedOn; Architecture = architecture; OperatingSystem = operatingSystem; + MediaType = mediaType; RelatedArtifacts = relatedArtifacts; Tags = tags; CanDelete = canDelete; @@ -78,6 +80,8 @@ internal ManifestAttributesBase(string digest, long? size, DateTimeOffset create public ArtifactArchitecture? Architecture { get; } /// Operating system. public ArtifactOperatingSystem? OperatingSystem { get; } + /// Media type. + public string MediaType { get; } /// List of artifacts that are referenced by this manifest list, with information about the platform each supports. This list will be empty if this is a leaf manifest and not a manifest list. public IReadOnlyList RelatedArtifacts { get; } /// List of tags. diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.Serialization.cs index 39fa2015238e..4665281c09db 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.Serialization.cs @@ -11,46 +11,15 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class ManifestList : IUtf8JsonSerializable + internal partial class ManifestList { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(MediaType)) - { - writer.WritePropertyName("mediaType"); - writer.WriteStringValue(MediaType); - } - if (Optional.IsCollectionDefined(Manifests)) - { - writer.WritePropertyName("manifests"); - writer.WriteStartArray(); - foreach (var item in Manifests) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - internal static ManifestList DeserializeManifestList(JsonElement element) { - Optional mediaType = default; - Optional> manifests = default; - Optional schemaVersion = default; + Optional> manifests = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { - if (property.NameEquals("mediaType")) - { - mediaType = property.Value.GetString(); - continue; - } if (property.NameEquals("manifests")) { if (property.Value.ValueKind == JsonValueKind.Null) @@ -68,16 +37,16 @@ internal static ManifestList DeserializeManifestList(JsonElement element) } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new ManifestList(Optional.ToNullable(schemaVersion), mediaType.Value, Optional.ToList(manifests)); + return new ManifestList(schemaVersion, mediaType, Optional.ToList(manifests)); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.cs index b4f028b7768a..3d9f61e26f9d 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestList.cs @@ -6,32 +6,33 @@ #nullable disable using System.Collections.Generic; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { /// Returns the requested Docker multi-arch-manifest file. - internal partial class ManifestList : Manifest + internal partial class ManifestList : ArtifactManifest { /// Initializes a new instance of ManifestList. - public ManifestList() + /// Schema version. + internal ManifestList(int schemaVersion) : base(schemaVersion) { Manifests = new ChangeTrackingList(); + MediaType = "application/vnd.docker.distribution.manifest.list.v2+json"; } /// Initializes a new instance of ManifestList. /// Schema version. /// Media type for this Manifest. /// List of V2 image layer information. - internal ManifestList(int? schemaVersion, string mediaType, IList manifests) : base(schemaVersion) + internal ManifestList(int schemaVersion, string mediaType, IReadOnlyList manifests) : base(schemaVersion, mediaType) { - MediaType = mediaType; Manifests = manifests; + MediaType = mediaType ?? "application/vnd.docker.distribution.manifest.list.v2+json"; } - /// Media type for this Manifest. - public string MediaType { get; set; } /// List of V2 image layer information. - public IList Manifests { get; } + public IReadOnlyList Manifests { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.Serialization.cs index c80aba9fbdf0..a5c198b2b0e7 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.Serialization.cs @@ -10,34 +10,8 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class ManifestListAttributes : IUtf8JsonSerializable + internal partial class ManifestListAttributes { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(MediaType)) - { - writer.WritePropertyName("mediaType"); - writer.WriteStringValue(MediaType); - } - if (Optional.IsDefined(Size)) - { - writer.WritePropertyName("size"); - writer.WriteNumberValue(Size.Value); - } - if (Optional.IsDefined(Digest)) - { - writer.WritePropertyName("digest"); - writer.WriteStringValue(Digest); - } - if (Optional.IsDefined(Platform)) - { - writer.WritePropertyName("platform"); - writer.WriteObjectValue(Platform); - } - writer.WriteEndObject(); - } - internal static ManifestListAttributes DeserializeManifestListAttributes(JsonElement element) { Optional mediaType = default; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.cs index e331df2719df..4c56d72504b2 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestListAttributes.cs @@ -11,7 +11,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class ManifestListAttributes { /// Initializes a new instance of ManifestListAttributes. - public ManifestListAttributes() + internal ManifestListAttributes() { } @@ -29,12 +29,12 @@ internal ManifestListAttributes(string mediaType, long? size, string digest, Pla } /// The MIME type of the referenced object. This will generally be application/vnd.docker.image.manifest.v2+json, but it could also be application/vnd.docker.image.manifest.v1+json. - public string MediaType { get; set; } + public string MediaType { get; } /// The size in bytes of the object. - public long? Size { get; set; } + public long? Size { get; } /// The digest of the content, as defined by the Registry V2 HTTP API Specification. - public string Digest { get; set; } + public string Digest { get; } /// The platform object describes the platform which the image in the manifest runs on. A full list of valid operating system and architecture values are listed in the Go language documentation for $GOOS and $GOARCH. - public Platform Platform { get; set; } + public Platform Platform { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.Serialization.cs index d91770e29e22..4c910c6afcef 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.Serialization.cs @@ -7,131 +7,29 @@ using System.Collections.Generic; using System.Text.Json; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { - internal partial class ManifestWrapper : IUtf8JsonSerializable + internal partial class ManifestWrapper { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(MediaType)) - { - writer.WritePropertyName("mediaType"); - writer.WriteStringValue(MediaType); - } - if (Optional.IsCollectionDefined(Manifests)) - { - writer.WritePropertyName("manifests"); - writer.WriteStartArray(); - foreach (var item in Manifests) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Config)) - { - writer.WritePropertyName("config"); - writer.WriteObjectValue(Config); - } - if (Optional.IsCollectionDefined(Layers)) - { - writer.WritePropertyName("layers"); - writer.WriteStartArray(); - foreach (var item in Layers) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Annotations)) - { - if (Annotations != null) - { - writer.WritePropertyName("annotations"); - writer.WriteObjectValue(Annotations); - } - else - { - writer.WriteNull("annotations"); - } - } - if (Optional.IsDefined(Architecture)) - { - writer.WritePropertyName("architecture"); - writer.WriteStringValue(Architecture); - } - if (Optional.IsDefined(Name)) - { - writer.WritePropertyName("name"); - writer.WriteStringValue(Name); - } - if (Optional.IsDefined(Tag)) - { - writer.WritePropertyName("tag"); - writer.WriteStringValue(Tag); - } - if (Optional.IsCollectionDefined(FsLayers)) - { - writer.WritePropertyName("fsLayers"); - writer.WriteStartArray(); - foreach (var item in FsLayers) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsCollectionDefined(History)) - { - writer.WritePropertyName("history"); - writer.WriteStartArray(); - foreach (var item in History) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsCollectionDefined(Signatures)) - { - writer.WritePropertyName("signatures"); - writer.WriteStartArray(); - foreach (var item in Signatures) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - internal static ManifestWrapper DeserializeManifestWrapper(JsonElement element) { - Optional mediaType = default; - Optional> manifests = default; - Optional config = default; - Optional> layers = default; - Optional annotations = default; + Optional> manifests = default; + Optional config = default; + Optional> layers = default; + Optional annotations = default; Optional architecture = default; Optional name = default; Optional tag = default; - Optional> fsLayers = default; - Optional> history = default; - Optional> signatures = default; - Optional schemaVersion = default; + Optional> fsLayers = default; + Optional> history = default; + Optional> signatures = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { - if (property.NameEquals("mediaType")) - { - mediaType = property.Value.GetString(); - continue; - } if (property.NameEquals("manifests")) { if (property.Value.ValueKind == JsonValueKind.Null) @@ -154,7 +52,7 @@ internal static ManifestWrapper DeserializeManifestWrapper(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - config = Descriptor.DeserializeDescriptor(property.Value); + config = ContentDescriptor.DeserializeContentDescriptor(property.Value); continue; } if (property.NameEquals("layers")) @@ -164,10 +62,10 @@ internal static ManifestWrapper DeserializeManifestWrapper(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - List array = new List(); + List array = new List(); foreach (var item in property.Value.EnumerateArray()) { - array.Add(Descriptor.DeserializeDescriptor(item)); + array.Add(ContentDescriptor.DeserializeContentDescriptor(item)); } layers = array; continue; @@ -179,7 +77,7 @@ internal static ManifestWrapper DeserializeManifestWrapper(JsonElement element) annotations = null; continue; } - annotations = Annotations.DeserializeAnnotations(property.Value); + annotations = OciManifestAnnotations.DeserializeOciManifestAnnotations(property.Value); continue; } if (property.NameEquals("architecture")) @@ -244,16 +142,16 @@ internal static ManifestWrapper DeserializeManifestWrapper(JsonElement element) } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new ManifestWrapper(Optional.ToNullable(schemaVersion), mediaType.Value, Optional.ToList(manifests), config.Value, Optional.ToList(layers), annotations.Value, architecture.Value, name.Value, tag.Value, Optional.ToList(fsLayers), Optional.ToList(history), Optional.ToList(signatures)); + return new ManifestWrapper(schemaVersion, mediaType, Optional.ToList(manifests), config.Value, Optional.ToList(layers), annotations.Value, architecture.Value, name.Value, tag.Value, Optional.ToList(fsLayers), Optional.ToList(history), Optional.ToList(signatures)); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.cs index cc785118e43e..e91506400e1a 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/ManifestWrapper.cs @@ -6,21 +6,24 @@ #nullable disable using System.Collections.Generic; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { /// Returns the requested manifest file. - internal partial class ManifestWrapper : Manifest + internal partial class ManifestWrapper : ArtifactManifest { /// Initializes a new instance of ManifestWrapper. - public ManifestWrapper() + /// Schema version. + internal ManifestWrapper(int schemaVersion) : base(schemaVersion) { Manifests = new ChangeTrackingList(); - Layers = new ChangeTrackingList(); + Layers = new ChangeTrackingList(); FsLayers = new ChangeTrackingList(); History = new ChangeTrackingList(); Signatures = new ChangeTrackingList(); + MediaType = "ManifestWrapper"; } /// Initializes a new instance of ManifestWrapper. @@ -36,9 +39,8 @@ public ManifestWrapper() /// (V1) List of layer information. /// (V1) Image history. /// (V1) Image signature. - internal ManifestWrapper(int? schemaVersion, string mediaType, IList manifests, Descriptor config, IList layers, Annotations annotations, string architecture, string name, string tag, IList fsLayers, IList history, IList signatures) : base(schemaVersion) + internal ManifestWrapper(int schemaVersion, string mediaType, IReadOnlyList manifests, ContentDescriptor config, IReadOnlyList layers, OciManifestAnnotations annotations, string architecture, string name, string tag, IReadOnlyList fsLayers, IReadOnlyList history, IReadOnlyList signatures) : base(schemaVersion, mediaType) { - MediaType = mediaType; Manifests = manifests; Config = config; Layers = layers; @@ -49,29 +51,28 @@ internal ManifestWrapper(int? schemaVersion, string mediaType, IList Media type for this Manifest. - public string MediaType { get; set; } /// (ManifestList, OCIIndex) List of V2 image layer information. - public IList Manifests { get; } + public IReadOnlyList Manifests { get; } /// (V2, OCI) Image config descriptor. - public Descriptor Config { get; set; } + public ContentDescriptor Config { get; } /// (V2, OCI) List of V2 image layer information. - public IList Layers { get; } + public IReadOnlyList Layers { get; } /// (OCI, OCIIndex) Additional metadata. - public Annotations Annotations { get; set; } + public OciManifestAnnotations Annotations { get; } /// (V1) CPU architecture. - public string Architecture { get; set; } + public string Architecture { get; } /// (V1) Image name. - public string Name { get; set; } + public string Name { get; } /// (V1) Image tag. - public string Tag { get; set; } + public string Tag { get; } /// (V1) List of layer information. - public IList FsLayers { get; } + public IReadOnlyList FsLayers { get; } /// (V1) Image history. - public IList History { get; } + public IReadOnlyList History { get; } /// (V1) Image signature. - public IList Signatures { get; } + public IReadOnlyList Signatures { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.Serialization.cs index 572e29da53e3..631411051689 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.Serialization.cs @@ -7,50 +7,19 @@ using System.Collections.Generic; using System.Text.Json; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { - internal partial class OCIIndex : IUtf8JsonSerializable + internal partial class OCIIndex { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsCollectionDefined(Manifests)) - { - writer.WritePropertyName("manifests"); - writer.WriteStartArray(); - foreach (var item in Manifests) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Annotations)) - { - if (Annotations != null) - { - writer.WritePropertyName("annotations"); - writer.WriteObjectValue(Annotations); - } - else - { - writer.WriteNull("annotations"); - } - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - internal static OCIIndex DeserializeOCIIndex(JsonElement element) { - Optional> manifests = default; - Optional annotations = default; - Optional schemaVersion = default; + Optional> manifests = default; + Optional annotations = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("manifests")) @@ -75,21 +44,21 @@ internal static OCIIndex DeserializeOCIIndex(JsonElement element) annotations = null; continue; } - annotations = Annotations.DeserializeAnnotations(property.Value); + annotations = OciManifestAnnotations.DeserializeOciManifestAnnotations(property.Value); continue; } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new OCIIndex(Optional.ToNullable(schemaVersion), Optional.ToList(manifests), annotations.Value); + return new OCIIndex(schemaVersion, mediaType, Optional.ToList(manifests), annotations.Value); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.cs index 3a38c71775fc..11aad75e85f1 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIIndex.cs @@ -6,32 +6,37 @@ #nullable disable using System.Collections.Generic; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { /// Returns the requested OCI index file. - internal partial class OCIIndex : Manifest + internal partial class OCIIndex : ArtifactManifest { /// Initializes a new instance of OCIIndex. - public OCIIndex() + /// Schema version. + internal OCIIndex(int schemaVersion) : base(schemaVersion) { Manifests = new ChangeTrackingList(); + MediaType = "application/vnd.oci.image.index.v1+json"; } /// Initializes a new instance of OCIIndex. /// Schema version. + /// Media type for this Manifest. /// List of OCI image layer information. /// Additional information provided through arbitrary metadata. - internal OCIIndex(int? schemaVersion, IList manifests, Annotations annotations) : base(schemaVersion) + internal OCIIndex(int schemaVersion, string mediaType, IReadOnlyList manifests, OciManifestAnnotations annotations) : base(schemaVersion, mediaType) { Manifests = manifests; Annotations = annotations; + MediaType = mediaType ?? "application/vnd.oci.image.index.v1+json"; } /// List of OCI image layer information. - public IList Manifests { get; } + public IReadOnlyList Manifests { get; } /// Additional information provided through arbitrary metadata. - public Annotations Annotations { get; set; } + public OciManifestAnnotations Annotations { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.Serialization.cs index 6ad79eb53969..75ad2d94555c 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.Serialization.cs @@ -9,54 +9,17 @@ using System.Text.Json; using Azure.Core; -namespace Azure.Containers.ContainerRegistry +namespace Azure.Containers.ContainerRegistry.Specialized { - internal partial class OCIManifest : IUtf8JsonSerializable + internal partial class OciManifest { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + internal static OciManifest DeserializeOciManifest(JsonElement element) { - writer.WriteStartObject(); - if (Optional.IsDefined(Config)) - { - writer.WritePropertyName("config"); - writer.WriteObjectValue(Config); - } - if (Optional.IsCollectionDefined(Layers)) - { - writer.WritePropertyName("layers"); - writer.WriteStartArray(); - foreach (var item in Layers) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Annotations)) - { - if (Annotations != null) - { - writer.WritePropertyName("annotations"); - writer.WriteObjectValue(Annotations); - } - else - { - writer.WriteNull("annotations"); - } - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - - internal static OCIManifest DeserializeOCIManifest(JsonElement element) - { - Optional config = default; - Optional> layers = default; - Optional annotations = default; - Optional schemaVersion = default; + Optional config = default; + Optional> layers = default; + Optional annotations = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("config")) @@ -66,7 +29,7 @@ internal static OCIManifest DeserializeOCIManifest(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - config = Descriptor.DeserializeDescriptor(property.Value); + config = ContentDescriptor.DeserializeContentDescriptor(property.Value); continue; } if (property.NameEquals("layers")) @@ -76,10 +39,10 @@ internal static OCIManifest DeserializeOCIManifest(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - List array = new List(); + List array = new List(); foreach (var item in property.Value.EnumerateArray()) { - array.Add(Descriptor.DeserializeDescriptor(item)); + array.Add(ContentDescriptor.DeserializeContentDescriptor(item)); } layers = array; continue; @@ -91,21 +54,21 @@ internal static OCIManifest DeserializeOCIManifest(JsonElement element) annotations = null; continue; } - annotations = Annotations.DeserializeAnnotations(property.Value); + annotations = OciManifestAnnotations.DeserializeOciManifestAnnotations(property.Value); continue; } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new OCIManifest(Optional.ToNullable(schemaVersion), config.Value, Optional.ToList(layers), annotations.Value); + return new OciManifest(schemaVersion, mediaType, config.Value, Optional.ToList(layers), annotations.Value); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.cs index 61167658a479..66242ad45264 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OCIManifest.cs @@ -8,34 +8,35 @@ using System.Collections.Generic; using Azure.Core; -namespace Azure.Containers.ContainerRegistry +namespace Azure.Containers.ContainerRegistry.Specialized { /// Returns the requested OCI Manifest file. - internal partial class OCIManifest : Manifest + internal partial class OciManifest : ArtifactManifest { - /// Initializes a new instance of OCIManifest. - public OCIManifest() + /// Initializes a new instance of OciManifest. + /// Schema version. + internal OciManifest(int schemaVersion) : base(schemaVersion) { - Layers = new ChangeTrackingList(); + Layers = new ChangeTrackingList(); + MediaType = "application/vnd.oci.image.manifest.v1+json"; } - /// Initializes a new instance of OCIManifest. + /// Initializes a new instance of OciManifest. /// Schema version. - /// V2 image config descriptor. + /// Media type for this Manifest. + /// V2 image config descriptor. /// List of V2 image layer information. /// Additional information provided through arbitrary metadata. - internal OCIManifest(int? schemaVersion, Descriptor config, IList layers, Annotations annotations) : base(schemaVersion) + internal OciManifest(int schemaVersion, string mediaType, ContentDescriptor configDescriptor, IReadOnlyList layers, OciManifestAnnotations annotations) : base(schemaVersion, mediaType) { - Config = config; + ConfigDescriptor = configDescriptor; Layers = layers; Annotations = annotations; + MediaType = mediaType ?? "application/vnd.oci.image.manifest.v1+json"; } - - /// V2 image config descriptor. - public Descriptor Config { get; set; } /// List of V2 image layer information. - public IList Layers { get; } + public IReadOnlyList Layers { get; } /// Additional information provided through arbitrary metadata. - public Annotations Annotations { get; set; } + public OciManifestAnnotations Annotations { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.Serialization.cs similarity index 55% rename from sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.Serialization.cs rename to sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.Serialization.cs index 265072eb0feb..08d4f635eda9 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.Serialization.cs @@ -10,82 +10,11 @@ using System.Text.Json; using Azure.Core; -namespace Azure.Containers.ContainerRegistry +namespace Azure.Containers.ContainerRegistry.Specialized { - internal partial class Annotations : IUtf8JsonSerializable + internal partial class OciManifestAnnotations { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Created)) - { - writer.WritePropertyName("org.opencontainers.image.created"); - writer.WriteStringValue(Created.Value, "O"); - } - if (Optional.IsDefined(Authors)) - { - writer.WritePropertyName("org.opencontainers.image.authors"); - writer.WriteStringValue(Authors); - } - if (Optional.IsDefined(Url)) - { - writer.WritePropertyName("org.opencontainers.image.url"); - writer.WriteStringValue(Url); - } - if (Optional.IsDefined(Documentation)) - { - writer.WritePropertyName("org.opencontainers.image.documentation"); - writer.WriteStringValue(Documentation); - } - if (Optional.IsDefined(Source)) - { - writer.WritePropertyName("org.opencontainers.image.source"); - writer.WriteStringValue(Source); - } - if (Optional.IsDefined(Version)) - { - writer.WritePropertyName("org.opencontainers.image.version"); - writer.WriteStringValue(Version); - } - if (Optional.IsDefined(Revision)) - { - writer.WritePropertyName("org.opencontainers.image.revision"); - writer.WriteStringValue(Revision); - } - if (Optional.IsDefined(Vendor)) - { - writer.WritePropertyName("org.opencontainers.image.vendor"); - writer.WriteStringValue(Vendor); - } - if (Optional.IsDefined(Licenses)) - { - writer.WritePropertyName("org.opencontainers.image.licenses"); - writer.WriteStringValue(Licenses); - } - if (Optional.IsDefined(Name)) - { - writer.WritePropertyName("org.opencontainers.image.ref.name"); - writer.WriteStringValue(Name); - } - if (Optional.IsDefined(Title)) - { - writer.WritePropertyName("org.opencontainers.image.title"); - writer.WriteStringValue(Title); - } - if (Optional.IsDefined(Description)) - { - writer.WritePropertyName("org.opencontainers.image.description"); - writer.WriteStringValue(Description); - } - foreach (var item in AdditionalProperties) - { - writer.WritePropertyName(item.Key); - writer.WriteObjectValue(item.Value); - } - writer.WriteEndObject(); - } - - internal static Annotations DeserializeAnnotations(JsonElement element) + internal static OciManifestAnnotations DeserializeOciManifestAnnotations(JsonElement element) { Optional orgOpencontainersImageCreated = default; Optional orgOpencontainersImageAuthors = default; @@ -99,7 +28,7 @@ internal static Annotations DeserializeAnnotations(JsonElement element) Optional orgOpencontainersImageRefName = default; Optional orgOpencontainersImageTitle = default; Optional orgOpencontainersImageDescription = default; - IDictionary additionalProperties = default; + IReadOnlyDictionary additionalProperties = default; Dictionary additionalPropertiesDictionary = new Dictionary(); foreach (var property in element.EnumerateObject()) { @@ -171,7 +100,7 @@ internal static Annotations DeserializeAnnotations(JsonElement element) additionalPropertiesDictionary.Add(property.Name, property.Value.GetObject()); } additionalProperties = additionalPropertiesDictionary; - return new Annotations(Optional.ToNullable(orgOpencontainersImageCreated), orgOpencontainersImageAuthors.Value, orgOpencontainersImageUrl.Value, orgOpencontainersImageDocumentation.Value, orgOpencontainersImageSource.Value, orgOpencontainersImageVersion.Value, orgOpencontainersImageRevision.Value, orgOpencontainersImageVendor.Value, orgOpencontainersImageLicenses.Value, orgOpencontainersImageRefName.Value, orgOpencontainersImageTitle.Value, orgOpencontainersImageDescription.Value, additionalProperties); + return new OciManifestAnnotations(Optional.ToNullable(orgOpencontainersImageCreated), orgOpencontainersImageAuthors.Value, orgOpencontainersImageUrl.Value, orgOpencontainersImageDocumentation.Value, orgOpencontainersImageSource.Value, orgOpencontainersImageVersion.Value, orgOpencontainersImageRevision.Value, orgOpencontainersImageVendor.Value, orgOpencontainersImageLicenses.Value, orgOpencontainersImageRefName.Value, orgOpencontainersImageTitle.Value, orgOpencontainersImageDescription.Value, additionalProperties); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.cs similarity index 75% rename from sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.cs rename to sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.cs index 7cc892496abc..da7778829a99 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Annotations.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/OciManifestAnnotations.cs @@ -9,18 +9,18 @@ using System.Collections.Generic; using Azure.Core; -namespace Azure.Containers.ContainerRegistry +namespace Azure.Containers.ContainerRegistry.Specialized { /// Additional information provided through arbitrary metadata. - internal partial class Annotations + internal partial class OciManifestAnnotations { - /// Initializes a new instance of Annotations. - public Annotations() + /// Initializes a new instance of OciManifestAnnotations. + internal OciManifestAnnotations() { AdditionalProperties = new ChangeTrackingDictionary(); } - /// Initializes a new instance of Annotations. + /// Initializes a new instance of OciManifestAnnotations. /// Date and time on which the image was built (string, date-time as defined by https://tools.ietf.org/html/rfc3339#section-5.6). /// Contact details of the people or organization responsible for the image. /// URL to find more information on the image. @@ -34,7 +34,7 @@ public Annotations() /// Human-readable title of the image. /// Human-readable description of the software packaged in the image. /// Additional Properties. - internal Annotations(DateTimeOffset? created, string authors, string url, string documentation, string source, string version, string revision, string vendor, string licenses, string name, string title, string description, IDictionary additionalProperties) + internal OciManifestAnnotations(DateTimeOffset? created, string authors, string url, string documentation, string source, string version, string revision, string vendor, string licenses, string name, string title, string description, IReadOnlyDictionary additionalProperties) { Created = created; Authors = authors; @@ -52,30 +52,30 @@ internal Annotations(DateTimeOffset? created, string authors, string url, string } /// Date and time on which the image was built (string, date-time as defined by https://tools.ietf.org/html/rfc3339#section-5.6). - public DateTimeOffset? Created { get; set; } + public DateTimeOffset? Created { get; } /// Contact details of the people or organization responsible for the image. - public string Authors { get; set; } + public string Authors { get; } /// URL to find more information on the image. - public string Url { get; set; } + public string Url { get; } /// URL to get documentation on the image. - public string Documentation { get; set; } + public string Documentation { get; } /// URL to get source code for building the image. - public string Source { get; set; } + public string Source { get; } /// Version of the packaged software. The version MAY match a label or tag in the source code repository, may also be Semantic versioning-compatible. - public string Version { get; set; } + public string Version { get; } /// Source control revision identifier for the packaged software. - public string Revision { get; set; } + public string Revision { get; } /// Name of the distributing entity, organization or individual. - public string Vendor { get; set; } + public string Vendor { get; } /// License(s) under which contained software is distributed as an SPDX License Expression. - public string Licenses { get; set; } + public string Licenses { get; } /// Name of the reference for a target. - public string Name { get; set; } + public string Name { get; } /// Human-readable title of the image. - public string Title { get; set; } + public string Title { get; } /// Human-readable description of the software packaged in the image. - public string Description { get; set; } + public string Description { get; } /// Additional Properties. - public IDictionary AdditionalProperties { get; } + public IReadOnlyDictionary AdditionalProperties { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.Serialization.cs index 0ae90b90d457..af74e480ec56 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.Serialization.cs @@ -11,62 +11,16 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class Platform : IUtf8JsonSerializable + internal partial class Platform { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Architecture)) - { - writer.WritePropertyName("architecture"); - writer.WriteStringValue(Architecture); - } - if (Optional.IsDefined(Os)) - { - writer.WritePropertyName("os"); - writer.WriteStringValue(Os); - } - if (Optional.IsDefined(OsVersion)) - { - writer.WritePropertyName("os.version"); - writer.WriteStringValue(OsVersion); - } - if (Optional.IsCollectionDefined(OsFeatures)) - { - writer.WritePropertyName("os.features"); - writer.WriteStartArray(); - foreach (var item in OsFeatures) - { - writer.WriteStringValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(Variant)) - { - writer.WritePropertyName("variant"); - writer.WriteStringValue(Variant); - } - if (Optional.IsCollectionDefined(Features)) - { - writer.WritePropertyName("features"); - writer.WriteStartArray(); - foreach (var item in Features) - { - writer.WriteStringValue(item); - } - writer.WriteEndArray(); - } - writer.WriteEndObject(); - } - internal static Platform DeserializePlatform(JsonElement element) { Optional architecture = default; Optional os = default; Optional osVersion = default; - Optional> osFeatures = default; + Optional> osFeatures = default; Optional variant = default; - Optional> features = default; + Optional> features = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("architecture")) diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.cs index cf78a2dcfe05..4aadf41587fa 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/Platform.cs @@ -14,7 +14,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class Platform { /// Initializes a new instance of Platform. - public Platform() + internal Platform() { OsFeatures = new ChangeTrackingList(); Features = new ChangeTrackingList(); @@ -27,7 +27,7 @@ public Platform() /// The optional os.features field specifies an array of strings, each listing a required OS feature (for example on Windows win32k. /// The optional variant field specifies a variant of the CPU, for example armv6l to specify a particular CPU variant of the ARM CPU. /// The optional features field specifies an array of strings, each listing a required CPU feature (for example sse4 or aes. - internal Platform(string architecture, string os, string osVersion, IList osFeatures, string variant, IList features) + internal Platform(string architecture, string os, string osVersion, IReadOnlyList osFeatures, string variant, IReadOnlyList features) { Architecture = architecture; Os = os; @@ -38,16 +38,16 @@ internal Platform(string architecture, string os, string osVersion, IList Specifies the CPU architecture, for example amd64 or ppc64le. - public string Architecture { get; set; } + public string Architecture { get; } /// The os field specifies the operating system, for example linux or windows. - public string Os { get; set; } + public string Os { get; } /// The optional os.version field specifies the operating system version, for example 10.0.10586. - public string OsVersion { get; set; } + public string OsVersion { get; } /// The optional os.features field specifies an array of strings, each listing a required OS feature (for example on Windows win32k. - public IList OsFeatures { get; } + public IReadOnlyList OsFeatures { get; } /// The optional variant field specifies a variant of the CPU, for example armv6l to specify a particular CPU variant of the ARM CPU. - public string Variant { get; set; } + public string Variant { get; } /// The optional features field specifies an array of strings, each listing a required CPU feature (for example sse4 or aes. - public IList Features { get; } + public IReadOnlyList Features { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/TagList.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/TagList.cs index 2ebab2e90dfc..ab23b070d981 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/TagList.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/TagList.cs @@ -15,7 +15,7 @@ namespace Azure.Containers.ContainerRegistry internal partial class TagList { /// Initializes a new instance of TagList. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// List of tag attribute details. /// , , or is null. @@ -40,7 +40,7 @@ internal TagList(string registryLoginServer, string repository, IEnumerable Initializes a new instance of TagList. - /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. /// Image name. /// List of tag attribute details. /// @@ -52,7 +52,7 @@ internal TagList(string registryLoginServer, string repository, IReadOnlyList Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. + /// Registry login server name. This is likely to be similar to {registry-name}.azurecr.io. public string RegistryLoginServer { get; } /// Image name. public string Repository { get; } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.Serialization.cs index a9e353b6da19..2b1db43a49e5 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.Serialization.cs @@ -11,73 +11,18 @@ namespace Azure.Containers.ContainerRegistry { - internal partial class V1Manifest : IUtf8JsonSerializable + internal partial class V1Manifest { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Architecture)) - { - writer.WritePropertyName("architecture"); - writer.WriteStringValue(Architecture); - } - if (Optional.IsDefined(Name)) - { - writer.WritePropertyName("name"); - writer.WriteStringValue(Name); - } - if (Optional.IsDefined(Tag)) - { - writer.WritePropertyName("tag"); - writer.WriteStringValue(Tag); - } - if (Optional.IsCollectionDefined(FsLayers)) - { - writer.WritePropertyName("fsLayers"); - writer.WriteStartArray(); - foreach (var item in FsLayers) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsCollectionDefined(History)) - { - writer.WritePropertyName("history"); - writer.WriteStartArray(); - foreach (var item in History) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsCollectionDefined(Signatures)) - { - writer.WritePropertyName("signatures"); - writer.WriteStartArray(); - foreach (var item in Signatures) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - internal static V1Manifest DeserializeV1Manifest(JsonElement element) { Optional architecture = default; Optional name = default; Optional tag = default; - Optional> fsLayers = default; - Optional> history = default; - Optional> signatures = default; - Optional schemaVersion = default; + Optional> fsLayers = default; + Optional> history = default; + Optional> signatures = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("architecture")) @@ -142,16 +87,16 @@ internal static V1Manifest DeserializeV1Manifest(JsonElement element) } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new V1Manifest(Optional.ToNullable(schemaVersion), architecture.Value, name.Value, tag.Value, Optional.ToList(fsLayers), Optional.ToList(history), Optional.ToList(signatures)); + return new V1Manifest(schemaVersion, mediaType, architecture.Value, name.Value, tag.Value, Optional.ToList(fsLayers), Optional.ToList(history), Optional.ToList(signatures)); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.cs index 5fdab4837ee1..b30aec3e2e60 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V1Manifest.cs @@ -6,30 +6,34 @@ #nullable disable using System.Collections.Generic; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { /// Returns the requested V1 manifest file. - internal partial class V1Manifest : Manifest + internal partial class V1Manifest : ArtifactManifest { /// Initializes a new instance of V1Manifest. - public V1Manifest() + /// Schema version. + internal V1Manifest(int schemaVersion) : base(schemaVersion) { FsLayers = new ChangeTrackingList(); History = new ChangeTrackingList(); Signatures = new ChangeTrackingList(); + MediaType = "application/vnd.docker.distribution.manifest.v1+json"; } /// Initializes a new instance of V1Manifest. /// Schema version. + /// Media type for this Manifest. /// CPU architecture. /// Image name. /// Image tag. /// List of layer information. /// Image history. /// Image signature. - internal V1Manifest(int? schemaVersion, string architecture, string name, string tag, IList fsLayers, IList history, IList signatures) : base(schemaVersion) + internal V1Manifest(int schemaVersion, string mediaType, string architecture, string name, string tag, IReadOnlyList fsLayers, IReadOnlyList history, IReadOnlyList signatures) : base(schemaVersion, mediaType) { Architecture = architecture; Name = name; @@ -37,19 +41,20 @@ internal V1Manifest(int? schemaVersion, string architecture, string name, string FsLayers = fsLayers; History = history; Signatures = signatures; + MediaType = mediaType ?? "application/vnd.docker.distribution.manifest.v1+json"; } /// CPU architecture. - public string Architecture { get; set; } + public string Architecture { get; } /// Image name. - public string Name { get; set; } + public string Name { get; } /// Image tag. - public string Tag { get; set; } + public string Tag { get; } /// List of layer information. - public IList FsLayers { get; } + public IReadOnlyList FsLayers { get; } /// Image history. - public IList History { get; } + public IReadOnlyList History { get; } /// Image signature. - public IList Signatures { get; } + public IReadOnlyList Signatures { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.Serialization.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.Serialization.cs index 6a5a33e2303f..fc4972c4c3f8 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.Serialization.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.Serialization.cs @@ -7,56 +7,21 @@ using System.Collections.Generic; using System.Text.Json; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { - internal partial class V2Manifest : IUtf8JsonSerializable + internal partial class V2Manifest { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(MediaType)) - { - writer.WritePropertyName("mediaType"); - writer.WriteStringValue(MediaType); - } - if (Optional.IsDefined(Config)) - { - writer.WritePropertyName("config"); - writer.WriteObjectValue(Config); - } - if (Optional.IsCollectionDefined(Layers)) - { - writer.WritePropertyName("layers"); - writer.WriteStartArray(); - foreach (var item in Layers) - { - writer.WriteObjectValue(item); - } - writer.WriteEndArray(); - } - if (Optional.IsDefined(SchemaVersion)) - { - writer.WritePropertyName("schemaVersion"); - writer.WriteNumberValue(SchemaVersion.Value); - } - writer.WriteEndObject(); - } - internal static V2Manifest DeserializeV2Manifest(JsonElement element) { - Optional mediaType = default; - Optional config = default; - Optional> layers = default; - Optional schemaVersion = default; + Optional config = default; + Optional> layers = default; + int schemaVersion = default; + string mediaType = default; foreach (var property in element.EnumerateObject()) { - if (property.NameEquals("mediaType")) - { - mediaType = property.Value.GetString(); - continue; - } if (property.NameEquals("config")) { if (property.Value.ValueKind == JsonValueKind.Null) @@ -64,7 +29,7 @@ internal static V2Manifest DeserializeV2Manifest(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - config = Descriptor.DeserializeDescriptor(property.Value); + config = ContentDescriptor.DeserializeContentDescriptor(property.Value); continue; } if (property.NameEquals("layers")) @@ -74,26 +39,26 @@ internal static V2Manifest DeserializeV2Manifest(JsonElement element) property.ThrowNonNullablePropertyIsNull(); continue; } - List array = new List(); + List array = new List(); foreach (var item in property.Value.EnumerateArray()) { - array.Add(Descriptor.DeserializeDescriptor(item)); + array.Add(ContentDescriptor.DeserializeContentDescriptor(item)); } layers = array; continue; } if (property.NameEquals("schemaVersion")) { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } schemaVersion = property.Value.GetInt32(); continue; } + if (property.NameEquals("mediaType")) + { + mediaType = property.Value.GetString(); + continue; + } } - return new V2Manifest(Optional.ToNullable(schemaVersion), mediaType.Value, config.Value, Optional.ToList(layers)); + return new V2Manifest(schemaVersion, mediaType, config.Value, Optional.ToList(layers)); } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.cs index df8a98230ffb..8ac6b36b3cda 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Generated/Models/V2Manifest.cs @@ -6,17 +6,20 @@ #nullable disable using System.Collections.Generic; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core; namespace Azure.Containers.ContainerRegistry { /// Returns the requested Docker V2 Manifest file. - internal partial class V2Manifest : Manifest + internal partial class V2Manifest : ArtifactManifest { /// Initializes a new instance of V2Manifest. - public V2Manifest() + /// Schema version. + internal V2Manifest(int schemaVersion) : base(schemaVersion) { - Layers = new ChangeTrackingList(); + Layers = new ChangeTrackingList(); + MediaType = "application/vnd.docker.distribution.manifest.v2+json"; } /// Initializes a new instance of V2Manifest. @@ -24,18 +27,16 @@ public V2Manifest() /// Media type for this Manifest. /// V2 image config descriptor. /// List of V2 image layer information. - internal V2Manifest(int? schemaVersion, string mediaType, Descriptor config, IList layers) : base(schemaVersion) + internal V2Manifest(int schemaVersion, string mediaType, ContentDescriptor config, IReadOnlyList layers) : base(schemaVersion, mediaType) { - MediaType = mediaType; Config = config; Layers = layers; + MediaType = mediaType ?? "application/vnd.docker.distribution.manifest.v2+json"; } - /// Media type for this Manifest. - public string MediaType { get; set; } /// V2 image config descriptor. - public Descriptor Config { get; set; } + public ContentDescriptor Config { get; } /// List of V2 image layer information. - public IList Layers { get; } + public IReadOnlyList Layers { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/GlobalSuppressions.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/GlobalSuppressions.cs index 989b59f6a6c2..576ffa48d84c 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/GlobalSuppressions.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/GlobalSuppressions.cs @@ -9,3 +9,4 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Usage", "AZC0001:Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure", Justification = "", Scope = "namespace", Target = "~N:Azure.Containers.ContainerRegistry")] +[assembly: SuppressMessage("Usage", "AZC0001:Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.Iot, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure", Justification = "", Scope = "namespace", Target = "~N:Azure.Containers.ContainerRegistry.Specialized")] diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/AcrManifests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/AcrManifests.cs index 3439c9fed321..c4f9708d0394 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/AcrManifests.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/AcrManifests.cs @@ -34,6 +34,7 @@ internal static ArtifactManifestProperties FromManifestAttributesBase(string reg attributesBase.LastUpdatedOn, attributesBase.Architecture, attributesBase.OperatingSystem, + attributesBase.MediaType, attributesBase.RelatedArtifacts, attributesBase.Tags, attributesBase.CanDelete, diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/ArtifactManifestProperties.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/ArtifactManifestProperties.cs index 1e1ed88843df..352deea6c212 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/ArtifactManifestProperties.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Models/ArtifactManifestProperties.cs @@ -29,5 +29,7 @@ public ArtifactManifestProperties() internal string QuarantineState { get; } /// Quarantine details. internal string QuarantineDetails { get; } + /// Media type. + internal string MediaType { get; } } } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Repository/ContainerRepository.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Repository/ContainerRepository.cs index a8e75a625452..720cf50188be 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Repository/ContainerRepository.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Repository/ContainerRepository.cs @@ -21,6 +21,7 @@ public partial class ContainerRepository { private readonly ClientDiagnostics _clientDiagnostics; private readonly ContainerRegistryRestClient _restClient; + private readonly ContainerRegistryBlobRestClient _blobRestClient; private readonly Uri _registryEndpoint; private readonly string _name; @@ -37,13 +38,14 @@ public partial class ContainerRepository /// /// - internal ContainerRepository(Uri registryEndpoint, string name, ClientDiagnostics clientDiagnostics, ContainerRegistryRestClient restClient) + internal ContainerRepository(Uri registryEndpoint, string name, ClientDiagnostics clientDiagnostics, ContainerRegistryRestClient restClient, ContainerRegistryBlobRestClient blobRestClient) { _name = name; _registryEndpoint = registryEndpoint; _clientDiagnostics = clientDiagnostics; _restClient = restClient; + _blobRestClient = blobRestClient; } /// Initializes a new instance of ContainerRepository for mocking. @@ -67,7 +69,8 @@ public virtual RegistryArtifact GetArtifact(string tagOrDigest) _name, tagOrDigest, _clientDiagnostics, - _restClient); + _restClient, + _blobRestClient); } #region Repository methods diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/autorest.md b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/autorest.md index 0a11ad9bdbd1..f7a5a0af5e29 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/autorest.md +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/autorest.md @@ -5,7 +5,21 @@ Run `dotnet build /t:GenerateCode` to generate code. ``` yaml title: Container Registry input-file: - - https://github.com/Azure/azure-rest-api-specs/blob/2c33d5572dab4c6f52faf31004f0561205737107/specification/containerregistry/data-plane/Azure.ContainerRegistry/stable/2021-07-01/containerregistry.json - +# - https://github.com/Azure/azure-rest-api-specs/blob/2c33d5572dab4c6f52faf31004f0561205737107/specification/containerregistry/data-plane/Azure.ContainerRegistry/stable/2021-07-01/containerregistry.json + - $(this-folder)/swagger/containerregistry.json model-namespace: false ``` + +# Add content-type parameter +``` yaml +directive: + from: swagger-document + where: $.paths["/v2/{name}/manifests/{reference}"].put + transform: > + $.parameters.push({ + "name": "Content-Type", + "in": "header", + "type": "string", + "description": "The manifest's Content-Type." + }); +``` diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/swagger/containerregistry.json b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/swagger/containerregistry.json new file mode 100644 index 000000000000..78dd068db407 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/swagger/containerregistry.json @@ -0,0 +1,3092 @@ +{ + "swagger": "2.0", + "info": { + "title": "Container Registry", + "description": "Metadata API definition for the Azure Container Registry runtime", + "version": "2019-08-15-preview" + }, + "x-ms-parameterized-host": { + "hostTemplate": "{url}", + "useSchemePrefix": false, + "positionInOperation": "first", + "parameters": [ + { + "$ref": "#/parameters/Url" + } + ] + }, + "securityDefinitions": { + "registry_auth": { + "type": "basic" + }, + "registry_oauth2": { + "type": "apiKey", + "in": "header", + "name": "Authorization" + } + }, + "security": [ + { + "registry_auth": [], + "registry_oauth2": [] + } + ], + "tags": [ + { + "name": "ContainerRegistry", + "description": "Registry Operations" + }, + { + "name": "ContainerRegistryBlob", + "description": "Blob Operations" + } + ], + "schemes": [ + "https" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v2/": { + "get": { + "tags": [ + "Registry" + ], + "description": "Tells whether this Docker Registry instance supports Docker Registry HTTP API v2", + "operationId": "ContainerRegistry_CheckDockerV2Support", + "x-ms-examples": { + "Check Docker Registry V2 Support": { + "$ref": "./examples/GetDockerRegistryV2Support.json" + } + }, + "responses": { + "200": { + "description": "Successful response. API v2 supported" + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/v2/{name}/manifests/{reference}": { + "get": { + "tags": [ + "Repository" + ], + "description": "Get the manifest identified by `name` and `reference` where `reference` can be a tag or digest.", + "x-ms-examples": { + "Get manifest": { + "$ref": "./examples/GetManifest.json" + } + }, + "operationId": "ContainerRegistry_GetManifest", + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/ImageReference" + }, + { + "name": "accept", + "in": "header", + "description": "Accept header string delimited by comma. For example, application/vnd.docker.distribution.manifest.v2+json", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Returns the requested manifest file in a larger combined group", + "schema": { + "$ref": "#/definitions/ManifestWrapper" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "put": { + "tags": [ + "Repository" + ], + "x-ms-long-running-operation": false, + "description": "Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest.", + "x-ms-examples": { + "Put manifest": { + "$ref": "./examples/CreateManifest.json" + } + }, + "consumes": [ + "application/vnd.docker.distribution.manifest.v2+json" + ], + "operationId": "ContainerRegistry_CreateManifest", + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/ImageReference" + }, + { + "$ref": "#/parameters/ManifestBody" + } + ], + "responses": { + "201": { + "description": "The manifest is updated", + "headers": { + "Docker-Content-Digest": { + "type": "string", + "description": "Identifies the docker upload uuid for the current request." + }, + "Location": { + "type": "string", + "description": "The canonical location url of the uploaded manifest." + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The length of the requested blob content." + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "delete": { + "tags": [ + "Repository" + ], + "description": "Delete the manifest identified by `name` and `reference`. Note that a manifest can _only_ be deleted by `digest`.", + "x-ms-examples": { + "Delete manifest": { + "$ref": "./examples/DeleteManifest.json" + } + }, + "operationId": "ContainerRegistry_DeleteManifest", + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/DigestReference" + } + ], + "responses": { + "202": { + "description": "The manifest has been deleted" + }, + "404": { + "description": "The manifest was not found" + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/v2/{name}/blobs/{digest}": { + "get": { + "produces": [ + "application/octet-stream" + ], + "tags": [ + "ContainerRegistryBlob" + ], + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + } + ], + "x-ms-examples": { + "Get a blob from digest": { + "$ref": "./examples/GetBlob.json" + } + }, + "description": "Retrieve the blob from the registry identified by digest.", + "operationId": "ContainerRegistryBlob_GetBlob", + "responses": { + "200": { + "description": "The blob identified by digest is available. The blob content will be present in the body of the response.", + "schema": { + "description": "blob binary data", + "type": "file", + "format": "file" + }, + "headers": { + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The length of the requested blob content." + }, + "Docker-Content-Digest": { + "description": "Digest of the targeted content for the request.", + "type": "string" + } + } + }, + "307": { + "description": "The blob identified by digest is available at the provided location.", + "headers": { + "Location": { + "type": "string", + "description": "The location where the layer should be accessible." + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "head": { + "tags": [ + "ContainerRegistryBlob" + ], + "description": "Same as GET, except only the headers are returned.", + "operationId": "ContainerRegistryBlob_CheckBlobExists", + "x-ms-examples": { + "Head for a Blob Chunk": { + "$ref": "./examples/CheckBlob.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + } + ], + "responses": { + "200": { + "description": "The blob identified by digest is available. The blob content will be present in the body of the response.", + "headers": { + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The length of the requested blob content." + }, + "Docker-Content-Digest": { + "description": "Digest of the targeted content for the request.", + "type": "string" + } + } + }, + "307": { + "description": "The blob identified by digest is available at the provided location.", + "headers": { + "Location": { + "type": "string", + "description": "The location where the layer should be accessible." + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "delete": { + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + } + ], + "description": "Removes an already uploaded blob.", + "produces": [ + "application/octet-stream" + ], + "tags": [ + "ContainerRegistryBlob" + ], + "operationId": "ContainerRegistryBlob_DeleteBlob", + "x-ms-examples": { + "Delete a blob": { + "$ref": "./examples/DeleteBlob.json" + } + }, + "responses": { + "202": { + "description": "The blob identified by digest is available. The blob content will be present in the body of the response.", + "schema": { + "description": "blob binary data", + "type": "file", + "format": "file" + }, + "headers": { + "Docker-Content-Digest": { + "description": "Digest of the targeted content for the request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/v2/{name}/blobs/uploads/": { + "post": { + "tags": [ + "ContainerRegistryBlob" + ], + "description": "Mount a blob identified by the `mount` parameter from another repository.", + "operationId": "ContainerRegistryBlob_MountBlob", + "x-ms-examples": { + "Mount a blob from repository": { + "$ref": "./examples/MountBlob.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/From" + }, + { + "$ref": "#/parameters/Mount" + } + ], + "responses": { + "201": { + "description": "The blob has been created in the registry and is available at the provided location.", + "headers": { + "Location": { + "description": "Provided location for blob", + "type": "string" + }, + "Docker-Upload-UUID": { + "description": "Identifies the docker upload uuid for the current request.", + "type": "string" + }, + "Docker-Content-Digest": { + "description": "Digest of the targeted content for the request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/{nextBlobUuidLink}": { + "get": { + "tags": [ + "ContainerRegistryBlob" + ], + "parameters": [ + { + "$ref": "#/parameters/NextLink" + } + ], + "description": "Retrieve status of upload identified by uuid. The primary purpose of this endpoint is to resolve the current status of a resumable upload.", + "operationId": "ContainerRegistryBlob_GetUploadStatus", + "x-ms-examples": { + "Get blob status": { + "$ref": "./examples/GetBlobStatus.json" + } + }, + "responses": { + "204": { + "description": "The upload is known and in progress. The last received offset is available in the Range header.", + "headers": { + "Range": { + "description": "Range indicating the current progress of the upload.", + "type": "string" + }, + "Docker-Upload-UUID": { + "description": "Identifies the docker upload uuid for the current request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "patch": { + "security": [ + { + "registry_auth": [], + "registry_oauth2": [] + } + ], + "tags": [ + "ContainerRegistryBlob" + ], + "description": "Upload a stream of data without completing the upload.", + "operationId": "ContainerRegistryBlob_UploadChunk", + "x-ms-examples": { + "Upload Blob": { + "$ref": "./examples/UploadBlob.json" + } + }, + "consumes": [ + "application/octet-stream" + ], + "parameters": [ + { + "$ref": "#/parameters/RawData" + }, + { + "$ref": "#/parameters/NextLink" + } + ], + "responses": { + "202": { + "description": "The stream of data has been accepted and the current progress is available in the range header. The updated upload location is available in the Location header.", + "headers": { + "Location": { + "description": "Provided location for blob", + "type": "string" + }, + "Range": { + "description": "Range indicating the current progress of the upload.", + "type": "string" + }, + "Docker-Upload-UUID": { + "description": "Identifies the docker upload uuid for the current request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "put": { + "tags": [ + "ContainerRegistryBlob" + ], + "consumes": [ + "application/octet-stream" + ], + "description": "Complete the upload, providing all the data in the body, if necessary. A request without a body will just complete the upload with previously uploaded content.", + "operationId": "ContainerRegistryBlob_CompleteUpload", + "x-ms-examples": { + "End a blob upload": { + "$ref": "./examples/EndBlobUpload.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/BlobQueryDigest" + }, + { + "$ref": "#/parameters/RawDataOptional" + }, + { + "$ref": "#/parameters/NextLink" + } + ], + "responses": { + "201": { + "description": "The upload has been completed and accepted by the registry.", + "headers": { + "Location": { + "description": "Provided location for blob", + "type": "string" + }, + "Range": { + "description": "Range indicating the current progress of the upload.", + "type": "string" + }, + "Docker-Content-Digest": { + "description": "Digest of the targeted content for the request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "delete": { + "tags": [ + "ContainerRegistryBlob" + ], + "parameters": [ + { + "$ref": "#/parameters/NextLink" + } + ], + "description": "Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout.", + "operationId": "ContainerRegistryBlob_CancelUpload", + "x-ms-examples": { + "End a blob upload": { + "$ref": "./examples/CancelBlobUpload.json" + } + }, + "responses": { + "204": { + "description": "The upload has been successfully deleted." + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/_catalog": { + "get": { + "tags": [ + "Registry" + ], + "description": "List repositories", + "operationId": "ContainerRegistry_GetRepositories", + "x-ms-pageable": { + "itemName": "repositories", + "nextLinkName": "link" + }, + "x-ms-examples": { + "Get repositories in a registry": { + "$ref": "./examples/GetRepositoryList.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/QueryLast" + }, + { + "$ref": "#/parameters/QueryNum" + } + ], + "responses": { + "200": { + "headers": { + "Link": { + "description": "next paginated result", + "type": "string" + } + }, + "description": "Returns a list of repositories", + "schema": { + "$ref": "#/definitions/Repositories" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/{name}": { + "get": { + "tags": [ + "Registry" + ], + "description": "Get repository attributes", + "operationId": "ContainerRegistry_GetProperties", + "x-ms-examples": { + "Get details of repository": { + "$ref": "./examples/GetRepositoryAttributes.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + } + ], + "responses": { + "200": { + "description": "Returns a list of attributes", + "schema": { + "$ref": "#/definitions/RepositoryAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "delete": { + "tags": [ + "Registry" + ], + "description": "Delete the repository identified by `name`", + "operationId": "ContainerRegistry_DeleteRepository", + "x-ms-examples": { + "Delete a repository": { + "$ref": "./examples/DeleteAcrRepository.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + } + ], + "responses": { + "202": { + "description": "The repository is deleted" + }, + "404": { + "description": "The repository was not found" + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "patch": { + "tags": [ + "Registry" + ], + "description": "Update the attribute identified by `name` where `reference` is the name of the repository.", + "operationId": "ContainerRegistry_UpdateProperties", + "x-ms-examples": { + "Update repository attributes": { + "$ref": "./examples/UpdateRepositoryAttributes.json" + } + }, + "consumes": [ + "application/json" + ], + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/RepositoryAttributeValue" + } + ], + "responses": { + "200": { + "description": "The attributes are updated", + "schema": { + "$ref": "#/definitions/RepositoryAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/{name}/_tags": { + "get": { + "tags": [ + "Repository" + ], + "description": "List tags of a repository", + "operationId": "ContainerRegistry_GetTags", + "x-ms-examples": { + "Get tags of a repository": { + "$ref": "./examples/GetTagList.json" + } + }, + "x-ms-pageable": { + "itemName": "tags", + "nextLinkName": "link" + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/QueryLast" + }, + { + "$ref": "#/parameters/QueryNum" + }, + { + "$ref": "#/parameters/QueryOrderBy" + }, + { + "$ref": "#/parameters/QueryDigest" + } + ], + "responses": { + "200": { + "headers": { + "Link": { + "description": "next paginated result", + "type": "string" + } + }, + "description": "Tag details of a repository", + "schema": { + "$ref": "#/definitions/TagList" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/{name}/_tags/{reference}": { + "get": { + "tags": [ + "Repository" + ], + "description": "Get tag attributes by tag", + "operationId": "ContainerRegistry_GetTagProperties", + "x-ms-examples": { + "Get tag attributes": { + "$ref": "./examples/GetTagAttributes.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/TagReference" + } + ], + "responses": { + "200": { + "description": "Tag attributes", + "schema": { + "$ref": "#/definitions/TagAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "patch": { + "tags": [ + "Repository" + ], + "description": "Update tag attributes", + "operationId": "ContainerRegistry_UpdateTagAttributes", + "consumes": [ + "application/json" + ], + "x-ms-examples": { + "Update attributes of a tag": { + "$ref": "./examples/UpdateTagAttributes.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/TagReference" + }, + { + "$ref": "#/parameters/TagAttributeValue" + } + ], + "responses": { + "200": { + "description": "The attributes are updated", + "schema": { + "$ref": "#/definitions/TagAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "delete": { + "tags": [ + "Repository" + ], + "description": "Delete tag", + "operationId": "ContainerRegistry_DeleteTag", + "consumes": [ + "application/json" + ], + "x-ms-examples": { + "Delete a tag": { + "$ref": "./examples/DeleteTag.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/TagReference" + } + ], + "responses": { + "202": { + "description": "The tag is deleted" + }, + "404": { + "description": "The tag was not found" + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/{name}/_manifests": { + "get": { + "tags": [ + "Repository" + ], + "description": "List manifests of a repository", + "operationId": "ContainerRegistry_GetManifests", + "x-ms-examples": { + "Get list of available manifests": { + "$ref": "./examples/GetManifestList.json" + } + }, + "x-ms-pageable": { + "itemName": "manifests", + "nextLinkName": "link" + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/QueryLast" + }, + { + "$ref": "#/parameters/QueryNum" + }, + { + "$ref": "#/parameters/QueryOrderBy" + } + ], + "responses": { + "200": { + "headers": { + "Link": { + "description": "next paginated result", + "type": "string" + } + }, + "description": "Returns a list of manifests", + "schema": { + "$ref": "#/definitions/AcrManifests" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/acr/v1/{name}/_manifests/{digest}": { + "get": { + "tags": [ + "Repository" + ], + "description": "Get manifest attributes", + "operationId": "ContainerRegistry_GetManifestProperties", + "x-ms-examples": { + "Get manifest attributes": { + "$ref": "./examples/GetManifestAttributes.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + } + ], + "responses": { + "200": { + "description": "List of attributes", + "schema": { + "$ref": "#/definitions/ManifestAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "patch": { + "tags": [ + "Repository" + ], + "description": "Update properties of a manifest", + "operationId": "ContainerRegistry_UpdateManifestProperties", + "consumes": [ + "application/json" + ], + "x-ms-examples": { + "Update attributes of a manifest": { + "$ref": "./examples/UpdateManifestAttributes.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + }, + { + "$ref": "#/parameters/ManifestAttributeValue" + } + ], + "responses": { + "200": { + "description": "The attributes are updated", + "schema": { + "$ref": "#/definitions/ManifestAttributes" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/oauth2/exchange": { + "post": { + "tags": [ + "AcrToken", + "RefreshToken" + ], + "description": "Exchange AAD tokens for an ACR refresh Token", + "operationId": "Authentication_ExchangeAadAccessTokenForAcrRefreshToken", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [ + { + "$ref": "#/parameters/Grant_type" + }, + { + "$ref": "#/parameters/Service" + }, + { + "$ref": "#/parameters/AccessToken" + } + ], + "responses": { + "200": { + "description": "ACR refresh token acquired", + "schema": { + "$ref": "#/definitions/RefreshToken" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + }, + "security": [], + "x-ms-examples": { + "Exchange AAD Token for ACR Refresh": { + "$ref": "./examples/PostRefreshToken.json" + } + } + } + }, + "/oauth2/token": { + "post": { + "tags": [ + "AcrToken", + "AccessToken" + ], + "description": "Exchange ACR Refresh token for an ACR Access Token", + "operationId": "Authentication_ExchangeAcrRefreshTokenForAcrAccessToken", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "parameters": [ + { + "$ref": "#/parameters/Service" + }, + { + "name": "scope", + "in": "formData", + "required": true, + "description": "Which is expected to be a valid scope, and can be specified more than once for multiple scope requests. You obtained this from the Www-Authenticate response header from the challenge.", + "type": "string" + }, + { + "name": "refresh_token", + "x-ms-client-name": "acrRefreshToken", + "in": "formData", + "required": true, + "description": "Must be a valid ACR refresh token", + "type": "string" + }, + { + "name": "grant_type", + "in": "formData", + "description": "Grant type is expected to be refresh_token", + "required": true, + "type": "string", + "enum": [ + "refresh_token", + "password" + ], + "x-ms-enum": { + "name": "TokenGrantType" + }, + "x-accessibility": "internal", + "x-ms-client-default": "refresh_token" + } + ], + "responses": { + "200": { + "description": "ACR access token acquired", + "schema": { + "$ref": "#/definitions/AccessToken" + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + }, + "security": [], + "x-ms-examples": { + "Get Access Token with Refresh Token": { + "$ref": "./examples/PostAccessToken.json" + } + } + } + } + }, + "x-ms-paths": { + "/v2/{name}/blobs/uploads/?mode=resumable": { + "post": { + "tags": [ + "ContainerRegistryBlob" + ], + "description": "Initiate a resumable blob upload with an empty request body.", + "operationId": "ContainerRegistryBlob_StartUpload", + "x-ms-examples": { + "Start a blob upload": { + "$ref": "./examples/StartBlobUpload.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/ImageName" + } + ], + "responses": { + "202": { + "description": "The upload has been created. The Location header must be used to complete the upload. The response should be identical to a GET request on the contents of the returned Location header.", + "headers": { + "Location": { + "description": "Provided location for blob", + "type": "string" + }, + "Range": { + "description": "Range indicating the current progress of the upload.", + "type": "string" + }, + "Docker-Upload-UUID": { + "description": "Identifies the docker upload uuid for the current request.", + "type": "string" + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + }, + "/v2/{name}/blobs/{digest}?mode=chunk": { + "get": { + "produces": [ + "application/octet-stream" + ], + "tags": [ + "ContainerRegistryBlob" + ], + "description": "Retrieve the blob from the registry identified by `digest`. This endpoint may also support RFC7233 compliant range requests. Support can be detected by issuing a HEAD request. If the header `Accept-Range: bytes` is returned, range requests can be used to fetch partial content.", + "operationId": "ContainerRegistryBlob_GetChunk", + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + }, + { + "$ref": "#/parameters/Range" + } + ], + "x-ms-examples": { + "Get a blob Chunk": { + "$ref": "./examples/GetBlobChunk.json" + } + }, + "responses": { + "206": { + "description": "The blob identified by digest is available. The specified chunk of blob content will be present in the body of the request.", + "schema": { + "description": "blob binary data", + "type": "file", + "format": "file" + }, + "headers": { + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The length of the requested blob content." + }, + "Content-Range": { + "type": "string", + "description": "Content range of blob chunk." + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + }, + "head": { + "tags": [ + "ContainerRegistryBlob" + ], + "parameters": [ + { + "$ref": "#/parameters/ImageName" + }, + { + "$ref": "#/parameters/Digest" + }, + { + "$ref": "#/parameters/Range" + } + ], + "description": "Same as GET, except only the headers are returned.", + "operationId": "ContainerRegistryBlob_CheckChunkExists", + "x-ms-examples": { + "Get headers without blob Chunk": { + "$ref": "./examples/CheckBlobChunk.json" + } + }, + "responses": { + "200": { + "description": "The blob identified by digest is available. The specified chunk of blob content will be present in the body of the request.", + "headers": { + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The length of the requested blob content." + }, + "Content-Range": { + "type": "string", + "description": "Content range of blob chunk." + } + } + }, + "default": { + "description": "ACR error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/AcrErrors" + } + } + } + } + } + }, + "definitions": { + "RepositoryAttributes": { + "required": [ + "registry", + "imageName", + "createdTime", + "lastUpdateTime", + "manifestCount", + "tagCount", + "changeableAttributes" + ], + "x-ms-client-name": "ContainerRepositoryProperties", + "type": "object", + "description": "Properties of this repository.", + "properties": { + "registry": { + "type": "string", + "readOnly": true, + "description": "Registry login server name. This is likely to be similar to {registry-name}.azurecr.io", + "x-ms-client-name": "registryLoginServer" + }, + "imageName": { + "type": "string", + "readOnly": true, + "description": "Image name", + "x-ms-client-name": "name" + }, + "createdTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Image created time", + "x-ms-client-name": "createdOn" + }, + "lastUpdateTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Image last update time", + "x-ms-client-name": "lastUpdatedOn" + }, + "manifestCount": { + "type": "integer", + "readOnly": true, + "description": "Number of the manifests" + }, + "tagCount": { + "type": "integer", + "readOnly": true, + "description": "Number of the tags" + }, + "changeableAttributes": { + "description": "Writeable properties of the resource", + "$ref": "#/definitions/RepositoryChangeableAttributes", + "x-ms-client-flatten": true + } + }, + "example": { + "registry": "registryname.azurecr.io", + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "imageName": "imageName", + "createdTime": "2018-09-07T16:30:46.6583219Z", + "tagCount": 6, + "manifestCount": 2, + "lastUpdateTime": "2018-09-07T16:30:46.6583219Z" + } + }, + "TagList": { + "required": [ + "registry", + "imageName", + "tags" + ], + "description": "List of tag details", + "x-accessibility": "internal", + "properties": { + "registry": { + "type": "string", + "description": "Registry login server name. This is likely to be similar to {registry-name}.azurecr.io", + "x-ms-client-name": "RegistryLoginServer" + }, + "imageName": { + "type": "string", + "description": "Image name", + "x-ms-client-name": "repository" + }, + "tags": { + "type": "array", + "description": "List of tag attribute details", + "x-ms-client-name": "TagAttributeBases", + "x-accessibility": "internal", + "items": { + "$ref": "#/definitions/TagAttributesBase" + } + }, + "link": { + "type": "string" + } + }, + "example": { + "registry": "registry", + "imageName": "imageName", + "tags": [ + { + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "name": "name", + "digest": "digest", + "createdTime": "createdTime", + "signed": true, + "lastUpdateTime": "lastUpdateTime" + }, + { + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "name": "name", + "digest": "digest", + "createdTime": "createdTime", + "signed": true, + "lastUpdateTime": "lastUpdateTime" + } + ] + } + }, + "TagAttributes": { + "required": [ + "registry", + "imageName", + "tag" + ], + "x-ms-client-name": "ArtifactTagProperties", + "description": "Tag attributes", + "properties": { + "registry": { + "type": "string", + "readOnly": true, + "description": "Registry login server name. This is likely to be similar to {registry-name}.azurecr.io", + "x-ms-client-name": "registryLoginServer" + }, + "imageName": { + "type": "string", + "readOnly": true, + "description": "Image name", + "x-ms-client-name": "repositoryName" + }, + "tag": { + "x-ms-client-flatten": true, + "description": "List of tag attribute details", + "readOnly": true, + "$ref": "#/definitions/TagAttributesBase" + } + }, + "example": { + "registry": "registry", + "imageName": "imageName", + "tag": { + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "name": "name", + "digest": "digest", + "createdTime": "createdTime", + "signed": true, + "lastUpdateTime": "lastUpdateTime" + } + } + }, + "TagAttributesBase": { + "required": [ + "name", + "digest", + "createdTime", + "lastUpdateTime", + "changeableAttributes" + ], + "description": "Tag attribute details", + "x-accessibility": "internal", + "properties": { + "name": { + "type": "string", + "readOnly": true, + "description": "Tag name" + }, + "digest": { + "type": "string", + "readOnly": true, + "description": "Tag digest" + }, + "createdTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Tag created time", + "x-ms-client-name": "createdOn" + }, + "lastUpdateTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Tag last update time", + "x-ms-client-name": "lastUpdatedOn" + }, + "changeableAttributes": { + "$ref": "#/definitions/TagChangeableAttributes", + "description": "Writeable properties of the resource", + "x-ms-client-flatten": true + } + }, + "example": { + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "name": "tagname", + "digest": "sha256:0873c923e00e0fd2ba78041bfb64a105e1ecb7678916d1f7776311e45bf5634b", + "createdTime": "2018-08-10T17:28:44.1082945Z", + "signed": true, + "lastUpdateTime": "2018-08-10T17:28:44.1082945Z" + } + }, + "TagOrderBy": { + "type": "string", + "enum": [ + "none", + "timedesc", + "timeasc" + ], + "x-ms-enum": { + "name": "ArtifactTagOrderBy", + "values": [ + { + "value": "none", + "name": "None", + "description": "Do not provide an orderby value in the request." + }, + { + "value": "timedesc", + "name": "LastUpdatedOnDescending", + "description": "Order tags by LastUpdatedOn field, from most recently updated to least recently updated." + }, + { + "value": "timeasc", + "name": "LastUpdatedOnAscending", + "description": "Order tags by LastUpdatedOn field, from least recently updated to most recently updated." + } + ] + }, + "x-accessibility": "public" + }, + "ArtifactArchitecture": { + "type": "string", + "enum": [ + "386", + "amd64", + "arm", + "arm64", + "mips", + "mipsle", + "mips64", + "mips64le", + "ppc64", + "ppc641e", + "riscv64", + "s390x", + "wasm" + ], + "x-ms-enum": { + "name": "ArtifactArchitecture", + "modelAsString": true, + "values": [ + { + "value": "386", + "name": "I386", + "description": "" + }, + { + "value": "amd64", + "name": "Amd64", + "description": "" + }, + { + "value": "arm", + "name": "Arm", + "description": "" + }, + { + "value": "arm64", + "name": "Arm64", + "description": "" + }, + { + "value": "mips", + "name": "Mips", + "description": "" + }, + { + "value": "mipsle", + "name": "MipsLe", + "description": "" + }, + { + "value": "mips64", + "name": "Mips64", + "description": "" + }, + { + "value": "mips64le", + "name": "Mips64Le", + "description": "" + }, + { + "value": "ppc64", + "name": "Ppc64", + "description": "" + }, + { + "value": "ppc64le", + "name": "Ppc64Le", + "description": "" + }, + { + "value": "riscv64", + "name": "RiscV64", + "description": "" + }, + { + "value": "s390x", + "name": "S390x", + "description": "" + }, + { + "value": "wasm", + "name": "Wasm", + "description": "" + } + ] + }, + "x-accessibility": "public" + }, + "ArtifactOperatingSystem": { + "type": "string", + "enum": [ + "aix", + "android", + "darwin", + "dragonfly", + "freebsd", + "illumos", + "ios", + "js", + "linux", + "netbsd", + "openbsd", + "plan9", + "solaris", + "windows" + ], + "x-ms-enum": { + "name": "ArtifactOperatingSystem", + "modelAsString": true, + "values": [ + { + "value": "aix", + "name": "Aix", + "description": "" + }, + { + "value": "android", + "name": "Android", + "description": "" + }, + { + "value": "darwin", + "name": "Darwin", + "description": "" + }, + { + "value": "dragonfly", + "name": "Dragonfly", + "description": "" + }, + { + "value": "freebsd", + "name": "FreeBsd", + "description": "" + }, + { + "value": "illumos", + "name": "Illumos", + "description": "" + }, + { + "value": "ios", + "name": "iOS", + "description": "" + }, + { + "value": "js", + "name": "JS", + "description": "" + }, + { + "value": "linux", + "name": "Linux", + "description": "" + }, + { + "value": "netbsd", + "name": "NetBsd", + "description": "" + }, + { + "value": "openbsd", + "name": "OpenBsd", + "description": "" + }, + { + "value": "plan9", + "name": "Plan9", + "description": "" + }, + { + "value": "solaris", + "name": "Solaris", + "description": "" + }, + { + "value": "windows", + "name": "Windows", + "description": "" + } + ] + }, + "x-accessibility": "public" + }, + "AcrManifests": { + "description": "Manifest attributes", + "properties": { + "registry": { + "type": "string", + "description": "Registry login server name. This is likely to be similar to {registry-name}.azurecr.io", + "x-ms-client-name": "registryLoginServer" + }, + "imageName": { + "type": "string", + "description": "Image name", + "x-ms-client-name": "repository" + }, + "manifests": { + "type": "array", + "description": "List of manifests", + "items": { + "$ref": "#/definitions/ManifestAttributesBase", + "description": "Manifest details" + } + }, + "link": { + "type": "string" + } + }, + "x-accessibility": "internal", + "example": { + "registry": "registry", + "imageName": "imageName", + "manifests": [ + { + "changeableAttributes": { + "quarantineDetails": "quarantineDetails", + "readEnabled": true, + "quarantineState": "quarantineState", + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "os": "os", + "digest": "digest", + "imageSize": 2401606, + "createdTime": "createdTime", + "mediaType": "mediaType", + "configMediaType": "configMediaType", + "lastUpdateTime": "lastUpdateTime", + "architecture": "architecture", + "tags": [ + "tags", + "tags" + ] + }, + { + "changeableAttributes": { + "quarantineDetails": "quarantineDetails", + "readEnabled": true, + "quarantineState": "quarantineState", + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "os": "os", + "digest": "digest", + "imageSize": 2401606, + "createdTime": "createdTime", + "mediaType": "mediaType", + "configMediaType": "configMediaType", + "lastUpdateTime": "lastUpdateTime", + "architecture": "architecture", + "tags": [ + "tags", + "tags" + ] + } + ] + } + }, + "ManifestAttributes": { + "required": [ + "manifest" + ], + "x-ms-client-name": "ArtifactManifestProperties", + "description": "Manifest attributes details", + "properties": { + "registry": { + "description": "Registry login server name. This is likely to be similar to {registry-name}.azurecr.io", + "readOnly": true, + "type": "string", + "x-ms-client-name": "registryLoginServer" + }, + "imageName": { + "description": "Repository name", + "type": "string", + "readOnly": true, + "x-ms-client-name": "repositoryName" + }, + "manifest": { + "x-ms-client-flatten": true, + "readOnly": true, + "description": "Manifest attributes", + "$ref": "#/definitions/ManifestAttributesBase" + } + }, + "example": { + "registry": "acrapi.azurecr-test.io", + "imageName": "nanoserver", + "manifest": { + "digest": "sha256:110d2b6c84592561338aa040b1b14b7ab81c2f9edbd564c2285dd7d70d777086", + "imageSize": 2401606, + "createdTime": "2018-09-06T06:17:20.9983915Z", + "lastUpdateTime": "2018-09-06T06:17:20.9983915Z", + "architecture": "amd64", + "os": "windows", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "configMediaType": "application/vnd.docker.container.image.v1+json", + "tags": [ + "4.7.2-20180905-nanoserver-1803" + ], + "changeableAttributes": { + "deleteEnabled": true, + "writeEnabled": true, + "readEnabled": true, + "listEnabled": true + } + } + } + }, + "ManifestAttributesBase": { + "required": [ + "digest", + "createdTime", + "lastUpdateTime" + ], + "type": "object", + "description": "Manifest details", + "x-accessibility": "internal", + "properties": { + "digest": { + "type": "string", + "readOnly": true, + "description": "Manifest" + }, + "imageSize": { + "type": "integer", + "readOnly": true, + "format": "int64", + "description": "Image size", + "x-ms-client-name": "size" + }, + "createdTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Created time", + "x-ms-client-name": "createdOn" + }, + "lastUpdateTime": { + "type": "string", + "readOnly": true, + "format": "date-time", + "description": "Last update time", + "x-ms-client-name": "lastUpdatedOn" + }, + "architecture": { + "$ref": "#/definitions/ArtifactArchitecture", + "description": "CPU architecture", + "readOnly": true, + "x-nullable": true + }, + "os": { + "$ref": "#/definitions/ArtifactOperatingSystem", + "description": "Operating system", + "x-ms-client-name": "operatingSystem", + "readOnly": true, + "x-nullable": true + }, + "mediaType": { + "x-accessibility": "internal", + "type": "string", + "description": "Media type" + }, + "references": { + "type": "array", + "readOnly": true, + "description": "List of artifacts that are referenced by this manifest list, with information about the platform each supports. This list will be empty if this is a leaf manifest and not a manifest list.", + "x-ms-client-name": "relatedArtifacts", + "items": { + "$ref": "#/definitions/ManifestAttributes_manifest_references", + "description": "Manifest attributes details" + } + }, + "tags": { + "type": "array", + "readOnly": true, + "description": "List of tags", + "items": { + "type": "string", + "description": "Tag name" + } + }, + "changeableAttributes": { + "$ref": "#/definitions/ManifestChangeableAttributes", + "description": "Writeable properties of the resource", + "x-ms-client-flatten": true + } + }, + "example": { + "changeableAttributes": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + }, + "os": "os", + "digest": "digest", + "imageSize": 2401606, + "createdTime": "createdTime", + "mediaType": "mediaType", + "configMediaType": "configMediaType", + "lastUpdateTime": "lastUpdateTime", + "architecture": "architecture", + "tags": [ + "tags", + "tags" + ] + } + }, + "RefreshToken": { + "type": "object", + "properties": { + "refresh_token": { + "description": "The refresh token to be used for generating access tokens", + "type": "string" + } + }, + "x-accessibility": "internal", + "x-ms-client-name": "AcrRefreshToken" + }, + "ManifestOrderBy": { + "type": "string", + "enum": [ + "none", + "timedesc", + "timeasc" + ], + "x-ms-enum": { + "name": "ArtifactManifestOrderBy", + "values": [ + { + "value": "none", + "name": "None", + "description": "Do not provide an orderby value in the request." + }, + { + "value": "timedesc", + "name": "LastUpdatedOnDescending", + "description": "Order manifests by LastUpdatedOn field, from most recently updated to least recently updated." + }, + { + "value": "timeasc", + "name": "LastUpdatedOnAscending", + "description": "Order manifest by LastUpdatedOn field, from least recently updated to most recently updated." + } + ] + }, + "default": "none", + "description": "Sort options for ordering manifests in a collection.", + "x-accessibility": "public" + }, + "AccessToken": { + "type": "object", + "properties": { + "access_token": { + "description": "The access token for performing authenticated requests", + "type": "string" + } + }, + "x-accessibility": "internal", + "x-ms-client-name": "AcrAccessToken" + }, + "AcrErrors": { + "description": "Acr error response describing why the operation failed", + "properties": { + "errors": { + "type": "array", + "description": "Array of detailed error", + "items": { + "$ref": "#/definitions/AcrErrorInfo" + } + } + } + }, + "RepositoryTags": { + "description": "Result of the request to list tags of the image", + "x-accessibility": "internal", + "properties": { + "name": { + "type": "string", + "description": "Name of the image" + }, + "tags": { + "type": "array", + "description": "List of tags", + "items": { + "type": "string", + "description": "Tag name" + } + } + }, + "example": { + "name": "name", + "tags": [ + "tags", + "tags" + ] + } + }, + "ImageSignature": { + "description": "Signature of a signed manifest", + "x-accessibility": "internal", + "properties": { + "header": { + "description": "A JSON web signature", + "$ref": "#/definitions/JWK" + }, + "signature": { + "type": "string", + "description": "A signature for the image manifest, signed by a libtrust private key" + }, + "protected": { + "type": "string", + "description": "The signed protected header" + } + }, + "example": { + "header": { + "jwk": { + "crv": "P-256", + "kid": "WGXM:EYWQ:DA53:LQUP:BCWG:5RDG:S3ZM:ETH7:VMQS:WWKZ:EWDG:V74Q", + "kty": "EC", + "x": "OxZ9k5BVjPZ7jb3BmBD4X0d8MVPJqfF4NeSe8reoqnY", + "y": "EaCqTe4-vYwhk7qU6Bs2-AeLGOVtCe_-IY2MdE0Vfyc" + }, + "alg": "ES256" + }, + "signature": "p73LfotMGD8nNXz2g9YX2XtSllb4GI5-b3vjqP5N0nkv8QXg-r5z_omGiVbOZE2BYG1X_4TIN23l1KSEqsXxOg", + "protected": "eyJmb3JtYXRMZW5ndGgiOjI5ODYsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxOC0wOS0yMFQyMzo0MTo1MloifQ" + } + }, + "JWK": { + "description": "A JSON web signature", + "x-accessibility": "internal", + "properties": { + "jwk": { + "$ref": "#/definitions/JWKHeader" + }, + "alg": { + "type": "string", + "description": "The algorithm used to sign or encrypt the JWT" + } + } + }, + "JWKHeader": { + "description": "JSON web key parameter", + "x-accessibility": "internal", + "properties": { + "crv": { + "type": "string", + "description": "crv value" + }, + "kid": { + "type": "string", + "description": "kid value" + }, + "kty": { + "type": "string", + "description": "kty value" + }, + "x": { + "type": "string", + "description": "x value" + }, + "y": { + "type": "string", + "description": "y value" + } + } + }, + "History": { + "description": "A list of unstructured historical data for v1 compatibility", + "x-accessibility": "internal", + "properties": { + "v1Compatibility": { + "type": "string", + "description": "The raw v1 compatibility information" + } + }, + "example": { + "v1Compatibility": "v1 compatibility info" + } + }, + "Repositories": { + "description": "List of repositories", + "properties": { + "repositories": { + "type": "array", + "description": "Repository names", + "items": { + "type": "string" + } + }, + "link": { + "type": "string" + } + }, + "x-accessibility": "internal", + "example": { + "repositories": [ + "production/alpine", + "testing/alpine" + ] + } + }, + "DeletedRepository": { + "x-ms-client-name": "DeleteRepositoryResult", + "description": "Deleted repository", + "properties": { + "manifestsDeleted": { + "type": "array", + "readOnly": true, + "description": "SHA of the deleted image", + "items": { + "type": "string" + }, + "x-ms-client-name": "deletedManifests" + }, + "tagsDeleted": { + "type": "array", + "readOnly": true, + "description": "Tag of the deleted image", + "items": { + "type": "string" + }, + "x-ms-client-name": "deletedTags" + } + } + }, + "AcrErrorInfo": { + "description": "Error information", + "properties": { + "code": { + "description": "Error code", + "type": "string" + }, + "message": { + "type": "string", + "description": "Error message" + }, + "detail": { + "type": "object", + "description": "Error details" + } + } + }, + "FsLayer": { + "description": "Image layer information", + "x-accessibility": "internal", + "properties": { + "blobSum": { + "type": "string", + "description": "SHA of an image layer" + } + }, + "example": { + "blobSum": "sha256:1f7d468f830cb0ed4beb8edc9438f18096e8c682e56a35242f60e6c61b718b30" + } + }, + "Descriptor": { + "description": "Docker V2 image layer descriptor including config and layers", + "x-accessibility": "internal", + "properties": { + "mediaType": { + "type": "string", + "description": "Layer media type" + }, + "size": { + "type": "integer", + "format": "int64", + "description": "Layer size" + }, + "digest": { + "type": "string", + "description": "Layer digest" + }, + "urls": { + "type": "array", + "description": "Specifies a list of URIs from which this object may be downloaded.", + "items": { + "description": "Must conform to RFC 3986. Entries should use the http and https schemes, as defined in RFC 7230.", + "type": "string" + } + }, + "annotations": { + "$ref": "#/definitions/Annotations" + } + }, + "example": { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2107098, + "digest": "sha256:5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6" + } + }, + "TagChangeableAttributes": { + "description": "Changeable attributes", + "x-ms-client-name": "TagWriteableProperties", + "x-accessibility": "internal", + "properties": { + "deleteEnabled": { + "type": "boolean", + "description": "Delete enabled", + "x-ms-client-name": "canDelete" + }, + "writeEnabled": { + "type": "boolean", + "description": "Write enabled", + "x-ms-client-name": "canWrite" + }, + "listEnabled": { + "type": "boolean", + "description": "List enabled", + "x-ms-client-name": "canList" + }, + "readEnabled": { + "type": "boolean", + "description": "Read enabled", + "x-ms-client-name": "canRead" + } + }, + "example": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + } + }, + "TagAttributes_tag": { + "description": "Tag", + "properties": { + "signatureRecord": { + "description": "SignatureRecord value", + "type": "string" + } + }, + "example": { + "signatureRecord": "signatureRecord" + } + }, + "ManifestAttributes_manifest_references": { + "required": [ + "digest" + ], + "x-ms-client-name": "ArtifactManifestPlatform", + "description": "Manifest attributes details", + "properties": { + "digest": { + "type": "string", + "readOnly": true, + "description": "Manifest digest" + }, + "architecture": { + "$ref": "#/definitions/ArtifactArchitecture", + "readOnly": true, + "description": "CPU architecture" + }, + "os": { + "$ref": "#/definitions/ArtifactOperatingSystem", + "readOnly": true, + "description": "Operating system", + "x-ms-client-name": "operatingSystem" + } + }, + "example": { + "os": "os", + "digest": "digest", + "architecture": "architecture" + } + }, + "ManifestAttributes_manifest": { + "description": "List of manifest attributes", + "properties": { + "references": { + "type": "array", + "description": "List of manifest attributes details", + "items": { + "$ref": "#/definitions/ManifestAttributes_manifest_references", + "description": "Manifest attributes details" + } + }, + "quarantineTag": { + "type": "string", + "description": "Quarantine tag name" + } + }, + "example": { + "quarantineTag": "quarantineTag", + "references": [ + { + "os": "os", + "digest": "digest", + "architecture": "architecture" + }, + { + "os": "os", + "digest": "digest", + "architecture": "architecture" + } + ] + } + }, + "ManifestChangeableAttributes": { + "description": "Changeable attributes", + "x-ms-client-name": "ManifestWriteableProperties", + "x-accessibility": "internal", + "properties": { + "deleteEnabled": { + "type": "boolean", + "description": "Delete enabled", + "x-ms-client-name": "canDelete" + }, + "writeEnabled": { + "type": "boolean", + "description": "Write enabled", + "x-ms-client-name": "canWrite" + }, + "listEnabled": { + "type": "boolean", + "description": "List enabled", + "x-ms-client-name": "canList" + }, + "readEnabled": { + "type": "boolean", + "description": "Read enabled", + "x-ms-client-name": "canRead" + }, + "quarantineState": { + "type": "string", + "description": "Quarantine state", + "x-accessibility": "internal" + }, + "quarantineDetails": { + "type": "string", + "description": "Quarantine details", + "x-accessibility": "internal" + } + }, + "example": { + "quarantineDetails": "quarantineDetails", + "readEnabled": true, + "quarantineState": "quarantineState", + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true + } + }, + "RepositoryChangeableAttributes": { + "description": "Changeable attributes for Repository", + "x-ms-client-name": "RepositoryWriteableProperties", + "x-accessibility": "internal", + "properties": { + "deleteEnabled": { + "type": "boolean", + "description": "Delete enabled", + "x-ms-client-name": "canDelete" + }, + "writeEnabled": { + "type": "boolean", + "description": "Write enabled", + "x-ms-client-name": "canWrite" + }, + "listEnabled": { + "type": "boolean", + "description": "List enabled", + "x-ms-client-name": "canList" + }, + "readEnabled": { + "type": "boolean", + "description": "Read enabled", + "x-ms-client-name": "canRead" + }, + "teleportEnabled": { + "type": "boolean", + "description": "Enables Teleport functionality on new images in the repository improving Container startup performance" + } + }, + "example": { + "readEnabled": true, + "listEnabled": true, + "deleteEnabled": true, + "writeEnabled": true, + "teleportEnabled": true + } + }, + "Manifest": { + "discriminator": "mediaType", + "required": [ + "mediaType", + "schemaVersion" + ], + "description": "Returns the requested manifest file", + "x-accessibility": "internal", + "properties": { + "schemaVersion": { + "type": "integer", + "description": "Schema version" + }, + "mediaType": { + "type": "string", + "description": "Media type for this Manifest" + } + } + }, + "ManifestWrapper": { + "description": "Returns the requested manifest file", + "x-accessibility": "internal", + "properties": { + "manifests": { + "type": "array", + "description": "(ManifestList, OCIIndex) List of V2 image layer information", + "items": { + "$ref": "#/definitions/ManifestListAttributes" + } + }, + "config": { + "description": "(V2, OCI) Image config descriptor", + "$ref": "#/definitions/Descriptor" + }, + "layers": { + "type": "array", + "description": "(V2, OCI) List of V2 image layer information", + "items": { + "$ref": "#/definitions/Descriptor" + } + }, + "annotations": { + "description": "(OCI, OCIIndex) Additional metadata", + "$ref": "#/definitions/Annotations" + }, + "architecture": { + "type": "string", + "description": "(V1) CPU architecture" + }, + "name": { + "type": "string", + "description": "(V1) Image name" + }, + "tag": { + "type": "string", + "description": "(V1) Image tag" + }, + "fsLayers": { + "type": "array", + "description": "(V1) List of layer information", + "items": { + "$ref": "#/definitions/FsLayer" + } + }, + "history": { + "type": "array", + "description": "(V1) Image history", + "items": { + "$ref": "#/definitions/History" + } + }, + "signatures": { + "type": "array", + "description": "(V1) Image signature", + "items": { + "$ref": "#/definitions/ImageSignature" + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ] + }, + "ManifestList": { + "x-ms-discriminator-value": "application/vnd.docker.distribution.manifest.list.v2+json", + "description": "Returns the requested Docker multi-arch-manifest file", + "x-accessibility": "internal", + "properties": { + "manifests": { + "type": "array", + "description": "List of V2 image layer information", + "items": { + "$ref": "#/definitions/ManifestListAttributes" + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ] + }, + "ManifestListAttributes": { + "x-accessibility": "internal", + "properties": { + "mediaType": { + "type": "string", + "description": "The MIME type of the referenced object. This will generally be application/vnd.docker.image.manifest.v2+json, but it could also be application/vnd.docker.image.manifest.v1+json" + }, + "size": { + "type": "integer", + "format": "int64", + "description": "The size in bytes of the object" + }, + "digest": { + "type": "string", + "description": "The digest of the content, as defined by the Registry V2 HTTP API Specification" + }, + "platform": { + "$ref": "#/definitions/Platform" + } + } + }, + "Platform": { + "description": "The platform object describes the platform which the image in the manifest runs on. A full list of valid operating system and architecture values are listed in the Go language documentation for $GOOS and $GOARCH", + "x-accessibility": "internal", + "properties": { + "architecture": { + "type": "string", + "description": "Specifies the CPU architecture, for example amd64 or ppc64le." + }, + "os": { + "type": "string", + "description": "The os field specifies the operating system, for example linux or windows." + }, + "os.version": { + "type": "string", + "description": "The optional os.version field specifies the operating system version, for example 10.0.10586." + }, + "os.features": { + "type": "array", + "description": "The optional os.features field specifies an array of strings, each listing a required OS feature (for example on Windows win32k", + "items": { + "type": "string" + } + }, + "variant": { + "type": "string", + "description": "The optional variant field specifies a variant of the CPU, for example armv6l to specify a particular CPU variant of the ARM CPU." + }, + "features": { + "type": "array", + "description": "The optional features field specifies an array of strings, each listing a required CPU feature (for example sse4 or aes", + "items": { + "type": "string" + } + } + } + }, + "V2Manifest": { + "x-ms-discriminator-value": "application/vnd.docker.distribution.manifest.v2+json", + "x-accessibility": "internal", + "description": "Returns the requested Docker V2 Manifest file", + "properties": { + "config": { + "description": "V2 image config descriptor", + "$ref": "#/definitions/Descriptor" + }, + "layers": { + "type": "array", + "description": "List of V2 image layer information", + "items": { + "$ref": "#/definitions/Descriptor" + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ], + "example": { + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1512, + "digest": "sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2107098, + "digest": "sha256:5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6" + } + ] + } + }, + "OCIManifest": { + "x-ms-discriminator-value": "application/vnd.oci.image.manifest.v1+json", + "x-accessibility": "internal", + "description": "Returns the requested OCI Manifest file", + "properties": { + "config": { + "description": "V2 image config descriptor", + "$ref": "#/definitions/Descriptor" + }, + "layers": { + "type": "array", + "description": "List of V2 image layer information", + "items": { + "$ref": "#/definitions/Descriptor" + } + }, + "annotations": { + "$ref": "#/definitions/Annotations" + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ] + }, + "OCIIndex": { + "x-ms-discriminator-value": "application/vnd.oci.image.index.v1+json", + "x-accessibility": "internal", + "description": "Returns the requested OCI index file", + "properties": { + "manifests": { + "type": "array", + "description": "List of OCI image layer information", + "items": { + "$ref": "#/definitions/ManifestListAttributes" + } + }, + "annotations": { + "$ref": "#/definitions/Annotations" + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ] + }, + "V1Manifest": { + "description": "Returns the requested V1 manifest file", + "x-ms-discriminator-value": "application/vnd.docker.distribution.manifest.v1+json", + "x-accessibility": "internal", + "properties": { + "architecture": { + "type": "string", + "description": "CPU architecture" + }, + "name": { + "type": "string", + "description": "Image name" + }, + "tag": { + "type": "string", + "description": "Image tag" + }, + "fsLayers": { + "type": "array", + "description": "List of layer information", + "items": { + "$ref": "#/definitions/FsLayer" + } + }, + "history": { + "type": "array", + "description": "Image history", + "items": { + "$ref": "#/definitions/History" + } + }, + "signatures": { + "type": "array", + "description": "Image signature", + "items": { + "$ref": "#/definitions/ImageSignature" + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/Manifest" + } + ] + }, + "Annotations": { + "description": "Additional information provided through arbitrary metadata.", + "x-accessibility": "internal", + "type": "object", + "x-nullable": true, + "additionalProperties": { + "type": "object" + }, + "properties": { + "org.opencontainers.image.created": { + "description": "Date and time on which the image was built (string, date-time as defined by https://tools.ietf.org/html/rfc3339#section-5.6)", + "type": "string", + "format": "date-time", + "x-ms-client-name": "Created" + }, + "org.opencontainers.image.authors": { + "description": "Contact details of the people or organization responsible for the image.", + "type": "string", + "x-ms-client-name": "Authors" + }, + "org.opencontainers.image.url": { + "description": "URL to find more information on the image.", + "type": "string", + "x-ms-client-name": "Url" + }, + "org.opencontainers.image.documentation": { + "description": "URL to get documentation on the image.", + "type": "string", + "x-ms-client-name": "Documentation" + }, + "org.opencontainers.image.source": { + "description": "URL to get source code for building the image.", + "type": "string", + "x-ms-client-name": "Source" + }, + "org.opencontainers.image.version": { + "description": "Version of the packaged software. The version MAY match a label or tag in the source code repository, may also be Semantic versioning-compatible", + "type": "string", + "x-ms-client-name": "Version" + }, + "org.opencontainers.image.revision": { + "description": "Source control revision identifier for the packaged software.", + "type": "string", + "x-ms-client-name": "Revision" + }, + "org.opencontainers.image.vendor": { + "description": "Name of the distributing entity, organization or individual.", + "type": "string", + "x-ms-client-name": "Vendor" + }, + "org.opencontainers.image.licenses": { + "description": "License(s) under which contained software is distributed as an SPDX License Expression.", + "type": "string", + "x-ms-client-name": "Licenses" + }, + "org.opencontainers.image.ref.name": { + "description": "Name of the reference for a target.", + "type": "string", + "x-ms-client-name": "Name" + }, + "org.opencontainers.image.title": { + "description": "Human-readable title of the image", + "type": "string", + "x-ms-client-name": "Title" + }, + "org.opencontainers.image.description": { + "description": "Human-readable description of the software packaged in the image", + "type": "string", + "x-ms-client-name": "Description" + } + } + } + }, + "parameters": { + "Url": { + "name": "url", + "x-ms-client-name": "loginUri", + "description": "Registry login URL", + "required": true, + "type": "string", + "in": "path", + "x-ms-skip-url-encoding": true, + "x-ms-parameter-location": "client" + }, + "ImageReference": { + "name": "reference", + "in": "path", + "description": "A tag or a digest, pointing to a specific image", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "ManifestReference": { + "name": "reference", + "in": "path", + "description": "Tag or digest of the target manifest", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "TagReference": { + "name": "reference", + "in": "path", + "description": "Tag name", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Digest": { + "name": "digest", + "in": "path", + "description": "Digest of a BLOB", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "DigestReference": { + "name": "reference", + "in": "path", + "description": "Digest of a BLOB", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "BlobQueryDigest": { + "name": "digest", + "in": "query", + "description": "Digest of a BLOB", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "RepositoryAttributeValue": { + "name": "value", + "in": "body", + "description": "Repository attribute value", + "required": false, + "schema": { + "$ref": "#/definitions/RepositoryChangeableAttributes" + }, + "x-ms-parameter-location": "method" + }, + "TagAttributeValue": { + "name": "value", + "in": "body", + "description": "Tag attribute value", + "required": false, + "schema": { + "$ref": "#/definitions/TagChangeableAttributes" + }, + "x-ms-parameter-location": "method" + }, + "ManifestAttributeValue": { + "name": "value", + "in": "body", + "description": "Manifest attribute value", + "required": false, + "schema": { + "$ref": "#/definitions/ManifestChangeableAttributes" + }, + "x-ms-parameter-location": "method" + }, + "QueryOrderBy": { + "name": "orderby", + "in": "query", + "description": "orderby query parameter", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "QueryNum": { + "name": "n", + "in": "query", + "description": "query parameter for max number of items", + "required": false, + "type": "integer", + "x-ms-parameter-location": "method" + }, + "QueryLast": { + "name": "last", + "in": "query", + "description": "Query parameter for the last item in previous query. Result set will include values lexically after last.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "QueryDigest": { + "name": "digest", + "in": "query", + "description": "filter by digest", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Grant_type": { + "name": "grant_type", + "description": "Can take a value of access_token", + "type": "string", + "in": "formData", + "required": true, + "enum": [ + "access_token" + ], + "x-ms-parameter-location": "method", + "x-accessibility": "internal" + }, + "Service": { + "name": "service", + "in": "formData", + "required": true, + "description": "Indicates the name of your Azure container registry.", + "type": "string", + "x-ms-parameter-location": "method" + }, + "Tenant": { + "name": "tenant", + "in": "formData", + "required": false, + "description": "AAD tenant associated to the AAD credentials.", + "type": "string", + "x-ms-parameter-location": "method" + }, + "Scope": { + "name": "scope", + "in": "formData", + "required": true, + "description": "Which is expected to be a valid scope, and can be specified more than once for multiple scope requests. You can obtain this from the Www-Authenticate response header from the challenge.", + "type": "string", + "x-ms-parameter-location": "method" + }, + "RefreshToken": { + "name": "refresh_token", + "in": "formData", + "required": false, + "description": "AAD refresh token, mandatory when grant_type is access_token_refresh_token or refresh_token", + "type": "string", + "x-ms-parameter-location": "method" + }, + "AccessToken": { + "name": "access_token", + "x-ms-client-name": "aadAccessToken", + "in": "formData", + "required": true, + "description": "AAD access token, mandatory when grant_type is access_token_refresh_token or access_token.", + "type": "string", + "x-ms-parameter-location": "method" + }, + "ImageName": { + "name": "name", + "in": "path", + "description": "Name of the image (including the namespace)", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "ManifestBody": { + "description": "Manifest body, can take v1 or v2 values depending on accept header", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "type": "string", + "format": "binary" + }, + "x-ms-parameter-location": "method" + }, + "RawData": { + "name": "value", + "description": "Raw data of blob", + "in": "body", + "schema": { + "type": "object", + "format": "file" + }, + "required": true, + "x-ms-parameter-location": "method" + }, + "RawDataOptional": { + "name": "value", + "description": "Optional raw data of blob", + "in": "body", + "schema": { + "type": "object", + "format": "file" + }, + "required": false, + "x-ms-parameter-location": "method" + }, + "From": { + "name": "from", + "type": "string", + "in": "query", + "description": "Name of the source repository.", + "required": true, + "x-ms-parameter-location": "method" + }, + "Mount": { + "name": "mount", + "description": "Digest of blob to mount from the source repository.", + "type": "string", + "in": "query", + "required": true, + "x-ms-parameter-location": "method" + }, + "Uuid": { + "name": "uuid", + "description": "A uuid identifying the upload.", + "type": "string", + "in": "path", + "required": true, + "x-ms-parameter-location": "method" + }, + "Content-Range": { + "name": "Content-Range", + "in": "header", + "description": "Range of bytes identifying the desired block of content represented by the body. Start must the end offset retrieved via status check plus one. Note that this is a non-standard use of the `Content-Range` header.", + "type": "string", + "required": true, + "x-ms-parameter-location": "method" + }, + "Range": { + "name": "Range", + "type": "string", + "description": "Format : bytes=-, HTTP Range header specifying blob chunk.", + "in": "header", + "required": true, + "x-ms-parameter-location": "method" + }, + "NoUploadCache": { + "description": "Acquired from NextLink", + "name": "_nouploadcache", + "in": "query", + "type": "boolean", + "required": false, + "x-ms-parameter-location": "method" + }, + "State": { + "description": "Acquired from NextLink", + "name": "_state", + "in": "query", + "type": "string", + "required": false, + "x-ms-parameter-location": "method" + }, + "NextLink": { + "name": "nextBlobUuidLink", + "x-ms-client-name": "nextLink", + "type": "string", + "description": "Link acquired from upload start or previous chunk. Note, do not include initial / (must do substring(1) )", + "in": "path", + "required": true, + "x-ms-parameter-location": "method", + "x-ms-skip-url-encoding": true + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientLiveTests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientLiveTests.cs new file mode 100644 index 000000000000..809c620bb84f --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientLiveTests.cs @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Threading.Tasks; +using Azure.Containers.ContainerRegistry.Specialized; +using Azure.Core.TestFramework; +using NUnit.Framework; +using System.Linq; + +namespace Azure.Containers.ContainerRegistry.Tests +{ + public class ContainerRegistryBlobClientLiveTests : ContainerRegistryRecordedTestBase + { + public ContainerRegistryBlobClientLiveTests(bool isAsync) : base(isAsync, RecordedTestMode.Live) + { + } + + [RecordedTest, NonParallelizable] + public async Task CanUploadOciManifest() + { + // Arrange + var client = CreateBlobClient("oci-artifact"); + var manifest = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data\\oci-artifact", "manifest.json"); + string digest = default; + + // Act + using (var fs = File.OpenRead(manifest)) + { + var uploadResult = await client.UploadManifestAsync(fs, new UploadManifestOptions() + { + MediaType = ManifestMediaType.OciManifest + }); + digest = uploadResult.Value.Digest; + } + + // Assert + var downloadResult = await client.DownloadManifestAsync(digest); + Assert.AreEqual(digest, downloadResult.Value.Digest); + Assert.AreEqual(ManifestMediaType.OciManifest, downloadResult.Value.MediaType); + + // Clean up + await client.DeleteManifestAsync(digest); + } + + [RecordedTest, NonParallelizable] + public async Task CanUploadOciManifestWithTag() + { + // Arrange + string repository = "oci-artifact"; + var client = CreateBlobClient(repository); + var metadataClient = CreateClient(); + var manifest = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data\\oci-artifact", "manifest.json"); + string digest = default; + string tag = $"v{DateTime.Now.Ticks}"; + + // Act + using (var fs = File.OpenRead(manifest)) + { + var uploadResult = await client.UploadManifestAsync(fs, new UploadManifestOptions() + { + Tag = tag, + MediaType = ManifestMediaType.OciManifest + }); + digest = uploadResult.Value.Digest; + } + + // Assert + var downloadResult = await client.DownloadManifestAsync(digest); + Assert.AreEqual(digest, downloadResult.Value.Digest); + Assert.AreEqual(ManifestMediaType.OciManifest, downloadResult.Value.MediaType); + + var artifact = metadataClient.GetArtifact(repository, digest); + var tags = artifact.GetTagPropertiesCollectionAsync(); + var count = await tags.CountAsync(); + Assert.AreEqual(1, count); + var firstTag = await tags.FirstAsync(); + Assert.AreEqual(tag, firstTag.Name); + + // Clean up + await client.DeleteManifestAsync(digest); + } + + [RecordedTest, NonParallelizable] + public async Task CanUploadBlob() + { + // Arrange + var client = CreateBlobClient("oci-artifact"); + var blob = "654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed"; + var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data\\oci-artifact", blob); + + string digest = default; + // Act + using (var fs = File.OpenRead(path)) + { + var uploadResult = await client.UploadBlobAsync(fs, new UploadBlobOptions()); + digest = uploadResult.Value.Digest; + } + + // Assert + var downloadResult = await client.DownloadBlobAsync(digest); + Assert.AreEqual(digest, downloadResult.Value.Digest); + Assert.AreEqual(28, downloadResult.Value.Content.Length); + + // Clean up + await client.DeleteBlobAsync(digest); + } + + [RecordedTest, NonParallelizable] + public async Task CanDownloadOciManifest() + { + // Arrange + var repository = "oci-artifact"; + var client = CreateBlobClient(repository); + var manifest = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data\\oci-artifact", "manifest.json"); + string digest = default; + + using (var fs = File.OpenRead(manifest)) + { + var uploadResult = await client.UploadManifestAsync(fs, new UploadManifestOptions() + { + MediaType = ManifestMediaType.OciManifest + }); + digest = uploadResult.Value.Digest; + } + + // Act + var downloadResult = await client.DownloadManifestAsync(digest); + + // Assert + + Assert.AreEqual(digest, downloadResult.Value.Digest); + Assert.AreEqual(ManifestMediaType.OciManifest, downloadResult.Value.MediaType); + + // Ensure known artifact files can be parsed from manifest data + Assert.IsNotNull(downloadResult.Value.ArtifactFiles); + Assert.AreEqual(2, downloadResult.Value.ArtifactFiles.Count); + + Assert.AreEqual("config.json", downloadResult.Value.ArtifactFiles[0].FileName); + Assert.AreEqual("sha256:d25b42d3dbad5361ed2d909624d899e7254a822c9a632b582ebd3a44f9b0dbc8", downloadResult.Value.ArtifactFiles[0].Digest); + Assert.AreEqual(repository, downloadResult.Value.ArtifactFiles[0].RepositoryName); + + Assert.IsNull(downloadResult.Value.ArtifactFiles[0].FileName); + Assert.AreEqual("sha256:654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed", downloadResult.Value.ArtifactFiles[0].Digest); + Assert.AreEqual(repository, downloadResult.Value.ArtifactFiles[0].RepositoryName); + + // Clean up + await client.DeleteManifestAsync(digest); + } + + [RecordedTest, NonParallelizable] + public async Task CanDownloadBlob() + { + // Arrange + var client = CreateBlobClient("oci-artifact"); + var blob = "654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed"; + var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data\\oci-artifact", blob); + + string digest = default; + + // Act + using (var fs = File.OpenRead(path)) + { + var uploadResult = await client.UploadBlobAsync(fs, new UploadBlobOptions()); + digest = uploadResult.Value.Digest; + } + + // Assert + var downloadResult = await client.DownloadBlobAsync(digest); + Assert.AreEqual(digest, downloadResult.Value.Digest); + Assert.AreEqual(28, downloadResult.Value.Content.Length); + + // Clean up + await client.DeleteBlobAsync(digest); + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientTests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientTests.cs new file mode 100644 index 000000000000..207f86111545 --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryBlobClientTests.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Containers.ContainerRegistry.Specialized; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Containers.ContainerRegistry.Tests +{ + public class ContainerRegistryBlobClientTests : ClientTestBase + { + public ContainerRegistryBlobClientTests(bool isAsync) : base(isAsync) + { + } + + private ContainerRegistryBlobClient client { get; set; } + private readonly Uri _url = new Uri("https://example.azurecr.io"); + + private TokenCredential GetCredential() + { + return new EnvironmentCredential(); + } + + [SetUp] + public void TestSetup() + { + client = InstrumentClient(new ContainerRegistryBlobClient(_url, GetCredential(), "", new ContainerRegistryClientOptions() + { + Audience = ContainerRegistryAudience.AzureResourceManagerPublicCloud + })); + } + + /// + /// Validates client constructor argument null checks. + /// + [Test] + public void ConstructorValidatesArguments() + { + // TODO: Complete these + + Assert.That(() => new ContainerRegistryClient(null, GetCredential()), Throws.InstanceOf(), "The constructor should validate the url."); + + Assert.That(() => new ContainerRegistryClient(_url, credential: null), Throws.InstanceOf(), "The constructor should not accept a null credential."); + + Assert.That(() => new ContainerRegistryClient(_url, GetCredential(), null), Throws.InstanceOf(), "The constructor should not accept null options."); + + Assert.That(() => new ContainerRegistryClient(_url, GetCredential()), Throws.InstanceOf(), "The constructor should not accept default ClientOptions"); + } + + /// + /// Validates service method argument null checks. + /// + [Test] + public void ServiceMethodsValidateArguments() + { + // TODO: Anything to address here? + } + } +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs index e62572704c78..717210b9954b 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Azure.Containers.ContainerRegistry.Specialized; using Azure.Core.TestFramework; using Azure.Identity; using Microsoft.Azure.Management.ContainerRegistry; @@ -48,6 +49,23 @@ private ContainerRegistryClient CreateAuthenticatedClient() )); } + public ContainerRegistryBlobClient CreateBlobClient(string repository) + { + string endpoint = TestEnvironment.Endpoint; + Uri authorityHost = GetAuthorityHost(endpoint); + ContainerRegistryAudience audience = GetAudience(authorityHost); + + return InstrumentClient(new ContainerRegistryBlobClient( + new Uri(endpoint), + TestEnvironment.Credential, + repository, + InstrumentClientOptions(new ContainerRegistryClientOptions() + { + Audience = audience + }) + )); + } + private ContainerRegistryClient CreateAnonymousClient() { string endpoint = TestEnvironment.AnonymousAccessEndpoint; diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRepositoryLiveTests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRepositoryLiveTests.cs index 6af89e26a96c..7fd9b7ed3868 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRepositoryLiveTests.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRepositoryLiveTests.cs @@ -14,7 +14,7 @@ public class ContainerRepositoryLiveTests : ContainerRegistryRecordedTestBase { private readonly string _repositoryName = "library/hello-world"; - public ContainerRepositoryLiveTests(bool isAsync) : base(isAsync) + public ContainerRepositoryLiveTests(bool isAsync) : base(isAsync, RecordedTestMode.Live) { } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed new file mode 100644 index 000000000000..80993781b54e Binary files /dev/null and b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/654b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed differ diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/config.json b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/config.json new file mode 100644 index 000000000000..2e34cd1899dc Binary files /dev/null and b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/config.json differ diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/manifest.json b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/manifest.json new file mode 100644 index 000000000000..fff3ab4daacf --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Data/oci-artifact/manifest.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 2, + "config": { + "mediaType": "application/vnd.acme.rocket.config", + "digest": "sha256:777b42d3dbad5361ed2d909624d899e7254a822c9a632b582ebd3a44f9b0dbc8", + "size": 171 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar", + "digest": "sha256:777b93f61054e4ce90ed203bb8d556a6200d5f906cf3eca0620738d6dc18cbed", + "size": 28, + "annotations": { + "org.opencontainers.image.title": "artifact.txt" + } + } + ] +} diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/RegistryArtifactLiveTests.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/RegistryArtifactLiveTests.cs index 287c9638a52c..bcbd2a7941b2 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/RegistryArtifactLiveTests.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/RegistryArtifactLiveTests.cs @@ -1,18 +1,22 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.IO; using System.Linq; using Azure.Core.TestFramework; using NUnit.Framework; using Task = System.Threading.Tasks.Task; +using Azure.Containers.ContainerRegistry.Specialized; +using Azure.Identity; namespace Azure.Containers.ContainerRegistry.Tests { public class RegistryArtifactLiveTests : ContainerRegistryRecordedTestBase { private readonly string _repositoryName = "library/hello-world"; + //private readonly string _repositoryName = "hello-artifact"; - public RegistryArtifactLiveTests(bool isAsync) : base(isAsync) + public RegistryArtifactLiveTests(bool isAsync) : base(isAsync, RecordedTestMode.Live) { } diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Samples/Sample05_OciPushPull.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Samples/Sample05_OciPushPull.cs new file mode 100644 index 000000000000..a1a57e6a2dbf --- /dev/null +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/Samples/Sample05_OciPushPull.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Azure.Containers.ContainerRegistry.Specialized; +using Azure.Core.TestFramework; +using NUnit.Framework; + +namespace Azure.Containers.ContainerRegistry.Tests.Samples +{ + public partial class OciPushPullSample : ContainerRegistrySamplesBase + { + [Test] + [AsyncOnly] + public async Task PullOciArtifactAsync() + { + Environment.SetEnvironmentVariable("REGISTRY_ENDPOINT", TestEnvironment.Endpoint); + + #region Snippet:ContainerRegistry_Tests_Samples_PullOciArtifactAsync + + // TODO: get these from configuration + var repository = "hello-artifact"; + var digest = "sha256:02d0a223fe27cbce4487d352e2fb36528ea69eb7958987f1ed21d75502a1f86d"; + string path = @"C:\temp\acr\test-oci-pull"; + + Uri endpoint = new Uri(Environment.GetEnvironmentVariable("REGISTRY_ENDPOINT")); + var downloadClient = new ContainerRegistryBlobClient(endpoint, new DefaultAzureCredential(), repository, new ContainerRegistryClientOptions() + { + Audience = ContainerRegistryAudience.AzureResourceManagerPublicCloud + }); + + // Get Manifest + var manifestResult = await downloadClient.DownloadManifestAsync(digest); + + // Write manifest to file + Directory.CreateDirectory(path); + string manifestFile = Path.Combine(path, "manifest.json"); + using (FileStream fs = File.Create(manifestFile)) + { + Stream stream = manifestResult.Value.Content; + await stream.CopyToAsync(fs).ConfigureAwait(false); + } + + // Write Config and Layers + foreach (var artifactFile in manifestResult.Value.ArtifactFiles) + { + string fileName = Path.Combine(path, artifactFile.FileName ?? TrimSha(artifactFile.Digest)); + + using (FileStream fs = File.Create(fileName)) + { + var layerResult = await downloadClient.DownloadBlobAsync(artifactFile.Digest); + await layerResult.Value.Content.CopyToAsync(fs).ConfigureAwait(false); + } + } + + #endregion + } + + private static string TrimSha(string digest) + { + int index = digest.IndexOf(':'); + if (index > -1) + { + return digest.Substring(index + 1); + } + + return digest; + } + + [Test] + [AsyncOnly] + public async Task PushOciArtifactAsync() + { + Environment.SetEnvironmentVariable("REGISTRY_ENDPOINT", TestEnvironment.Endpoint); + + #region Snippet:ContainerRegistry_Tests_Samples_PushOciArtifactAsync + + // TODO: get these from configuration + var repository = "hello-artifact"; + string path = @"C:\temp\acr\test-oci-push"; + + Uri endpoint = new Uri(Environment.GetEnvironmentVariable("REGISTRY_ENDPOINT")); + var uploadClient = new ContainerRegistryBlobClient(endpoint, new DefaultAzureCredential(), repository, new ContainerRegistryClientOptions() + { + Audience = ContainerRegistryAudience.AzureResourceManagerPublicCloud + }); + + var manifestFilePath = Path.Combine(path, "manifest.json"); + foreach (var file in Directory.GetFiles(path)) + { + using (var fs = File.OpenRead(file)) + { + if (file == manifestFilePath) + { + //await uploadClient.UploadManifestAsync(fs, + // new UploadManifestOptions(ManifestMediaType.OciManifestV1) + //); + } + else + { + await uploadClient.UploadBlobAsync(fs); + } + } + } + + #endregion + } + } +}