private async Task PushTemplateSet(ContainerRegistryInfo registry, string repository, string tag) { AzureContainerRegistryClient acrClient = new AzureContainerRegistryClient(registry.Server, new AcrBasicToken(registry)); int schemaV2 = 2; string mediatypeV2Manifest = "application/vnd.docker.distribution.manifest.v2+json"; string mediatypeV1Manifest = "application/vnd.oci.image.config.v1+json"; string emptyConfigStr = "{}"; // Upload config blob byte[] originalConfigBytes = Encoding.UTF8.GetBytes(emptyConfigStr); using var originalConfigStream = new MemoryStream(originalConfigBytes); string originalConfigDigest = ComputeDigest(originalConfigStream); await UploadBlob(acrClient, originalConfigStream, repository, originalConfigDigest); // Upload memory blob using Stream byteStream = Samples.GetDefaultConversionTemplates(); var blobLength = byteStream.Length; string blobDigest = ComputeDigest(byteStream); await UploadBlob(acrClient, byteStream, repository, blobDigest); // Push manifest List <Descriptor> layers = new List <Descriptor> { new Descriptor("application/vnd.oci.image.layer.v1.tar", blobLength, blobDigest), }; var v2Manifest = new V2Manifest(schemaV2, mediatypeV2Manifest, new Descriptor(mediatypeV1Manifest, originalConfigBytes.Length, originalConfigDigest), layers); await acrClient.Manifests.CreateAsync(repository, tag, v2Manifest); }
public ContainerRegistryDataPlaneClient(IAzureContext context) { _clientCredential = AzureSession.Instance.AuthenticationFactory.GetServiceClientCredentials(context, AzureEnvironment.Endpoint.ResourceManager); _accessToken = AzureSession.Instance.AuthenticationFactory.Authenticate(context.Account, context.Environment, context.Tenant.Id, null, ShowDialog.Never, null, context.Environment.GetTokenAudience(AzureEnvironment.Endpoint.ResourceManager)); _suffix = context.Environment.ContainerRegistryEndpointSuffix; _client = AzureSession.Instance.ClientFactory.CreateCustomArmClient <AzureContainerRegistryClient>(_clientCredential); }
public static async Task GenerateTemplateImageAsync(ImageInfo imageInfo, string accessToken, string templateFilePath) { AzureContainerRegistryClient acrClient = new AzureContainerRegistryClient(imageInfo.Registry, new AcrBasicToken(accessToken)); int schemaV2 = 2; string mediatypeV2Manifest = "application/vnd.docker.distribution.manifest.v2+json"; string mediatypeV1Manifest = "application/vnd.oci.image.config.v1+json"; string emptyConfigStr = "{}"; // Upload config blob byte[] originalConfigBytes = Encoding.UTF8.GetBytes(emptyConfigStr); using var originalConfigStream = new MemoryStream(originalConfigBytes); string originalConfigDigest = ComputeDigest(originalConfigStream); await UploadBlob(acrClient, originalConfigStream, imageInfo.ImageName, originalConfigDigest); // Upload memory blob List <Descriptor> layers = new List <Descriptor>(); using FileStream fileStream = File.OpenRead(templateFilePath); using MemoryStream byteStream = new MemoryStream(); fileStream.CopyTo(byteStream); var blobLength = byteStream.Length; string blobDigest = ComputeDigest(byteStream); await UploadBlob(acrClient, byteStream, imageInfo.ImageName, blobDigest); layers.Add(new Descriptor("application/vnd.oci.image.layer.v1.tar", blobLength, blobDigest)); // Push manifest var v2Manifest = new V2Manifest(schemaV2, mediatypeV2Manifest, new Descriptor(mediatypeV1Manifest, originalConfigBytes.Length, originalConfigDigest), layers); await acrClient.Manifests.CreateAsync(imageInfo.ImageName, imageInfo.Tag, v2Manifest); }
/// <summary> /// /// </summary> /// <param name="userName"></param> /// <param name="password"></param> /// <param name="loginServer"></param> /// <returns></returns> public static async ValueTask <AcrRepository[]> LoadAsync(string userName, string password, string loginServer) { //--- create client var credentials = new BasicAuthenticationCredentials { UserName = userName.Trim(), Password = password.Trim(), }; var client = new AzureContainerRegistryClient(credentials) { BaseUri = new Uri($"https://{loginServer.Trim()}"), }; //--- load reposigories var names = (await client.GetRepositoriesAsync().ConfigureAwait(false)).Names; return((await names .Select(async x => { var manifests = (await client.GetAcrManifestsAsync(x).ConfigureAwait(false)) .Manifests .OrderByDescending(y => y.CreatedTime) .Select(y => new AcrManifest(y)) .ToArray(); return new AcrRepository(x, manifests); }) .WhenAll() .ConfigureAwait(false)) .OrderBy(x => x.Name) .ToArray()); }
private static AzureContainerRegistryClient LoginBasic(CancellationToken ct, string username, string password, string loginUrl) { AcrClientCredentials credentials = new AcrClientCredentials(AcrClientCredentials.LoginMode.Basic, loginUrl, username, password, ct); AzureContainerRegistryClient client = new AzureContainerRegistryClient(credentials); client.LoginUri = "https://" + loginUrl; return(client); }
static void Main() { int timeoutInMilliseconds = 1500000; CancellationToken ct = new CancellationTokenSource(timeoutInMilliseconds).Token; AzureContainerRegistryClient client = LoginBasic(ct); BuildImageInRepoAfterDownload(RepoOrigin, RepoOutput, OutputTag, client, ct).GetAwaiter().GetResult(); }
public ContainerRegistryDataPlaneClient(IAzureContext context, string acrTokenCacheKey) { _context = context; _suffix = _context.Environment.ContainerRegistryEndpointSuffix; ServiceClientCredentials clientCredential = AzureSession.Instance.AuthenticationFactory.GetServiceClientCredentials(_accessToken, () => _accessToken); _client = AzureSession.Instance.ClientFactory.CreateCustomArmClient <AzureContainerRegistryClient>(clientCredential); _acrTokenCacheKey = acrTokenCacheKey; }
private static async Task UploadBlob(AzureContainerRegistryClient acrClient, Stream stream, string repository, string digest) { stream.Position = 0; var uploadInfo = await acrClient.Blob.StartUploadAsync(repository); var uploadedLayer = await acrClient.Blob.UploadAsync(stream, uploadInfo.Location); await acrClient.Blob.EndUploadAsync(digest, uploadedLayer.Location); }
/// <summary> /// Example Credentials provisioning (Using Basic Authentication) /// </summary> private static AzureContainerRegistryClient LoginBasic(CancellationToken ct) { AcrClientCredentials credentials = new AcrClientCredentials(AcrClientCredentials.LoginMode.Basic, Registry, Username, Password, ct); AzureContainerRegistryClient client = new AzureContainerRegistryClient(credentials) { LoginUri = "https://csharpsdkblobtest.azurecr.io" }; return(client); }
public async Task GetAcrAccessTokenFromLogin() { using (var context = MockContext.Start(GetType(), nameof(GetAcrAccessTokenFromLogin))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); var accessToken = await client.AccessTokens.GetFromLoginAsync(ACRTestUtil.ManagedTestRegistryFullName, ACRTestUtil.Scope); ValidateAccessToken(accessToken.AccessTokenProperty); } }
public async Task GetAcrRefreshTokenFromExchange() { using (var context = MockContext.Start(GetType(), nameof(GetAcrRefreshTokenFromExchange))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); var refreshToken = await client.RefreshTokens.GetFromExchangeAsync("access_token", ACRTestUtil.ManagedTestRegistryFullName, null, null, await ACRTestUtil.GetAADAccessToken()); ValidateRefreshToken(refreshToken.RefreshTokenProperty); } }
public async Task CancelBlobUpload() { using (var context = MockContext.Start(GetType(), nameof(CancelBlobUpload))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistryForChanges); var uploadInfo = await client.Blob.StartUploadAsync(ACRTestUtil.changeableRepository); await client.Blob.CancelUploadAsync(uploadInfo.Location); } }
public async Task CheckBlob() { using (var context = MockContext.Start(GetType(), nameof(CheckBlob))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); var blob = await client.Blob.CheckAsync(ACRTestUtil.ProdRepository, ProdConfigBlobDigest); Assert.Equal(blob.DockerContentDigest, ProdConfigBlobDigest); Assert.Equal(5635, blob.ContentLength); } }
public async Task CheckBlobChunk() { using (var context = MockContext.Start(GetType(), nameof(CheckBlobChunk))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); var blobData = await client.Blob.CheckChunkAsync(ACRTestUtil.ProdRepository, ProdConfigBlobDigest, "bytes=0-300"); //Range is actually ignored in this request. Ends up working quite similarly to CheckBlob Assert.Equal(5635, blobData.ContentLength); } }
private static async System.Threading.Tasks.Task DeleteImageAsync( ContainerRegistryImageDeletedEventData deleteEvent, AppConfiguration configuration, ILogger log) { // Create the resourceId from the target ACR resourceId string var targetACRResourceId = ResourceId.FromString(configuration.TargetACRResourceId); // Create Azure credentials to talk to target Cloud using the Active directory application var credential = new AzureCredentials( new ServicePrincipalLoginInformation { ClientId = configuration.TargetAzureServicePrincipalClientId, ClientSecret = configuration.TargetAzureServicePrincipalClientKey }, configuration.TargetAzureServicePrincipalTenantId, AzureEnvironment.FromName(configuration.TargetAzureEnvironmentName)) .WithDefaultSubscription(targetACRResourceId.SubscriptionId); var builder = RestClient .Configure() .WithEnvironment(AzureEnvironment.FromName(configuration.TargetAzureEnvironmentName)) .WithCredentials(credential) .Build(); // Create ACR management client using the Azure credentials var _registryClient = new ContainerRegistryManagementClient(builder); _registryClient.SubscriptionId = targetACRResourceId.SubscriptionId; // Fetch the target ACR properties to identify its login server. var targetRegistry = await _registryClient.Registries.GetAsync( resourceGroupName : targetACRResourceId.ResourceGroupName, registryName : targetACRResourceId.Name) ?? throw new InvalidOperationException($"'{configuration.TargetACRResourceId}' is not found"); // Create ACR data plane client using the Azure credentials var registryCredentials = new ContainerRegistryCredentials( ContainerRegistryCredentials.LoginMode.TokenAuth, targetRegistry.LoginServer, configuration.TargetAzureServicePrincipalClientId, configuration.TargetAzureServicePrincipalClientKey); var client = new AzureContainerRegistryClient(registryCredentials); // Invoke Delete of the image that is part of the delete event on the target ACR. await client.Manifests.DeleteAsync( name : deleteEvent.Target.Repository, reference : deleteEvent.Target.Digest); log.LogInformation($"Image '{deleteEvent.Target.Repository}:@{deleteEvent.Target.Digest}' deleted from registry '{configuration.TargetACRResourceId}'"); }
public async Task GetBlob() { using (var context = MockContext.Start(GetType(), nameof(GetBlob))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); Stream blob = await client.Blob.GetAsync(ACRTestUtil.ProdRepository, ProdConfigBlobDigest); StreamReader reader = new StreamReader(blob, Encoding.UTF8); string originalBlob = reader.ReadToEnd(); Assert.Equal(ProdConfigBlob, originalBlob); } }
public async Task GetBlobOAuth() { using (var context = MockContext.Start(GetType(), nameof(GetBlobOAuth))) { LoginMode loginMode = LoginMode.TokenAuth; // use oauth - exchange username and password for a refreshtoken AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry, loginMode); Stream blob = await client.Blob.GetAsync(ACRTestUtil.ProdRepository, ProdConfigBlobDigest); StreamReader reader = new StreamReader(blob, Encoding.UTF8); string originalBlob = reader.ReadToEnd(); Assert.Equal(ProdConfigBlob, originalBlob); } }
public async Task DeleteBlob() { using (var context = MockContext.Start(GetType(), nameof(DeleteBlob))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistryForChanges); string digest = await UploadLayer(GenerateStreamFromString("Testdata"), client, ACRTestUtil.BlobTestRepository); await client.Blob.DeleteAsync(ACRTestUtil.BlobTestRepository, digest); // Should not find layer Assert.Throws <AcrErrorsException>(() => { client.Blob.CheckAsync(ACRTestUtil.BlobTestRepository, digest).GetAwaiter().GetResult(); }); // Should error } }
public async Task UploadLayerNext() { using (var context = MockContext.Start(GetType(), nameof(UploadLayerNext))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); string digest = await UploadLayer(GenerateStreamFromString("SomethingElse"), client, ACRTestUtil.BlobTestRepository); var blob = await client.Blob.GetAsync(ACRTestUtil.BlobTestRepository, digest); StreamReader reader = new StreamReader(blob, Encoding.UTF8); Assert.Equal("SomethingElse", reader.ReadToEnd()); } }
public async Task GetBlobStatus() { using (var context = MockContext.Start(GetType(), nameof(GetBlobStatus))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistry); var uploadInfo = await client.Blob.StartUploadAsync(ACRTestUtil.BlobTestRepository); var status = await client.Blob.GetStatusAsync(uploadInfo.Location.Substring(1)); Assert.Equal(uploadInfo.DockerUploadUUID, status.DockerUploadUUID); Assert.Equal("0-0", status.Range); await client.Blob.CancelUploadAsync(uploadInfo.Location); } }
public async Task MountBlob() { using (var context = MockContext.Start(GetType(), nameof(MountBlob))) { AzureContainerRegistryClient client = await ACRTestUtil.GetACRClientAsync(context, ACRTestUtil.ManagedTestRegistryForChanges); var res = await client.Blob.MountAsync("somethingnew", "doundo/bash", "sha256:16463e0c481e161aabb735437d30b3c9c7391c2747cc564bb927e843b73dcb39"); Stream blob = await client.Blob.GetAsync("somethingnew", "sha256:16463e0c481e161aabb735437d30b3c9c7391c2747cc564bb927e843b73dcb39"); StreamReader reader = new StreamReader(blob, Encoding.UTF8); string originalBlob = reader.ReadToEnd(); Assert.Equal(ProdConfigBlob, originalBlob); } }
private async Task <string> UploadLayer(Stream blob, AzureContainerRegistryClient client, string repository) { // Make copy to obtain the ability to rewind the stream Stream cpy = new MemoryStream(); blob.CopyTo(cpy); cpy.Position = 0; string digest = ComputeDigest(cpy); cpy.Position = 0; var uploadInfo = await client.Blob.StartUploadAsync(repository); var uploadedLayer = await client.Blob.UploadAsync(cpy, uploadInfo.Location); var uploadedLayerEnd = await client.Blob.EndUploadAsync(digest, uploadedLayer.Location); return(uploadedLayerEnd.DockerContentDigest); }
/// <summary> /// Upload a layer using the nextLink properties internally. Very clean and simple to use overall. /// </summary> private static async Task <string> UploadLayer(Stream blob, string repo, AzureContainerRegistryClient client) { // Make copy to obtain the ability to rewind the stream Stream cpy = new MemoryStream(); blob.CopyTo(cpy); cpy.Position = 0; string digest = ComputeDigest(cpy); cpy.Position = 0; var uploadInfo = await client.StartEmptyResumableBlobUploadAsync(repo); var uploadedLayer = await client.UploadBlobContentFromNextAsync(cpy, uploadInfo.Location.Substring(1)); var uploadedLayerEnd = await client.EndBlobUploadFromNextAsync(digest, uploadedLayer.Location.Substring(1)); return(digest); }
static void Main(string[] args) { string username = "******"; string password = ""; string loginUrl = "acryihchentest0611.azurecr.io"; int timeoutInMilliseconds = 15000; CancellationToken ct = new CancellationTokenSource(timeoutInMilliseconds).Token; AcrClientCredentials clientCredential = new AcrClientCredentials(true, loginUrl, username, password, ct); AzureContainerRegistryClient client = new AzureContainerRegistryClient(clientCredential); client.LoginUri = "https://acryihchentest0611.azurecr.io"; try { /* * { * // ######################## Acr V1 Get Repositories ######################## * Repositories repositories = client.GetAcrRepositoriesAsync(null, * "", * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/_catalog result"); * Console.WriteLine(SafeJsonConvert.SerializeObject(repositories, client.SerializationSettings)); * foreach (string repository in repositories.Names) { * // ######################## Acr V1 Get Repositorie Attributes ######################## * RepositoryAttributes repositoryAttributes = client.GetAcrRepositoryAttributesAsync(repository, * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/{0} result", repository); * Console.WriteLine(SafeJsonConvert.SerializeObject(repositoryAttributes, client.SerializationSettings)); * * // ######################## Acr V1 Get Repositorie Tags ######################## * AcrRepositoryTags tags = client.GetAcrTagsAsync(repository, * null, * null, * null, * null, * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/{0}/_tags result", repository); * Console.WriteLine(SafeJsonConvert.SerializeObject(tags, client.SerializationSettings)); * foreach (AcrTagAttributesBase tag in tags.TagsAttributes) { * // ######################## Acr V1 Get Tag Attributes ######################## * AcrTagAttributes tagAttribute = client.GetAcrTagAttributesAsync(repository, * tag.Name, * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/{0}/_tags/{1} result", repository, tag.Name); * Console.WriteLine(SafeJsonConvert.SerializeObject(tagAttribute, client.SerializationSettings)); * } * * // ######################## Acr V1 Get Repositorie Manifests ######################## * AcrManifests manifests = client.GetAcrManifestsAsync(repository, * null, * null, * null, * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/{0}/_manifests result", repository); * Console.WriteLine(SafeJsonConvert.SerializeObject(manifests, client.SerializationSettings)); * foreach (AcrManifestAttributesBase manifest in manifests.ManifestsAttributes) { * // ######################## Acr V1 Get Manifest Attributes ######################## * AcrManifestAttributes manifestAttribute = client.GetAcrManifestAttributesAsync(repository, * manifest.Digest, * ct).GetAwaiter().GetResult(); * Console.WriteLine("GET /acr/v1/{0}/_manifests/{1} result", repository, manifest.Digest); * Console.WriteLine(SafeJsonConvert.SerializeObject(manifestAttribute, client.SerializationSettings)); * } * } * }*/ { // ######################## Docker V2 Get Repositories ######################## Repositories repositories = client.GetRepositoriesAsync(null, null, ct).GetAwaiter().GetResult(); Console.WriteLine("GET /v2/_catalog result"); Console.WriteLine(SafeJsonConvert.SerializeObject(repositories, client.SerializationSettings)); foreach (string repository in repositories.Names) { // ######################## Docker V2 Get Tags ######################## RepositoryTags repositoryTags = client.GetTagListAsync(repository, ct).GetAwaiter().GetResult(); Console.WriteLine("GET /v2/{0}/tags/list result", repository); Console.WriteLine(SafeJsonConvert.SerializeObject(repositoryTags, client.SerializationSettings)); foreach (string tag in repositoryTags.Tags) { // ######################## Docker V2 Get Manifest ######################## Manifest manifest = client.GetManifestAsync(repository, tag, "application/vnd.docker.distribution.manifest.v2+json", // most of docker images are v2 docker images now. The accept header should include "application/vnd.docker.distribution.manifest.v2+json" ct).GetAwaiter().GetResult(); Console.WriteLine("GET /v2/{0}/manifests/{1} result", repository, tag); Console.WriteLine(SafeJsonConvert.SerializeObject(manifest, client.SerializationSettings)); // ######################## Docker V2 Update Manifest ######################## // Use the same manifest to update the manifest // Keep in mind, you need to wait at least 5 seconds to let this change be committed in server. // Getting manifest again right after updating will actually getting old manifest. if (!string.Equals(tag, "3.7")) { continue; } // 1. Reference by tag client.PutManifestAsync(repository, tag, // Reference by tag manifest, ct).GetAwaiter().GetResult(); Console.WriteLine("PUT /v2/{0}/manifests/{1} result. reference by tag", repository, tag); Console.WriteLine(SafeJsonConvert.SerializeObject(manifest, client.SerializationSettings)); // 2. Reference by digest string manifestString = SafeJsonConvert.SerializeObject(manifest, client.SerializationSettings); string digest = computeDigest(manifestString); client.PutManifestAsync(repository, digest, // Reference by digest manifest, ct).GetAwaiter().GetResult(); Console.WriteLine("PUT /v2/{0}/manifests/{1} result. reference by digest", repository, digest); Console.WriteLine(SafeJsonConvert.SerializeObject(manifest, client.SerializationSettings)); } } } } catch (Exception e) { Console.WriteLine("Exception caught: " + e.Message); } }
private static async Task CopyBaseImageLayers(ImageRef origin, ImageRef output, bool includeConfig) { AzureContainerRegistryClient originClient; if (!string.IsNullOrEmpty(origin.Username)) { var originCredentials = new AcrClientCredentials(AcrClientCredentials.LoginMode.Basic, origin.Registry, origin.Username, origin.Password); originClient = new AzureContainerRegistryClient(originCredentials) { LoginUri = origin.Registry }; } else { originClient = new AzureContainerRegistryClient(new TokenCredentials()) { LoginUri = "https://" + origin.Registry }; } var outputCredentials = new AcrClientCredentials(AcrClientCredentials.LoginMode.Basic, output.Registry, output.Username, output.Password); var outputClient = new AzureContainerRegistryClient(outputCredentials) { LoginUri = "https://" + output.Registry }; V2Manifest manifest = (V2Manifest)await originClient.GetManifestAsync(origin.Repository, origin.Tag, "application/vnd.docker.distribution.manifest.v2+json"); var listOfActions = new List <Action>(); // Acquire and upload all layers for (int i = 0; i < manifest.Layers.Count; i++) { var cur = i; listOfActions.Add(() => { var progress = new ProgressBar(3); progress.Refresh(0, "Starting"); var layer = originClient.GetBlobAsync(origin.Repository, manifest.Layers[cur].Digest).GetAwaiter().GetResult(); progress.Next("Downloading " + manifest.Layers[cur].Digest + " layer from " + origin); string digestLayer = UploadLayer(layer, output.Repository, outputClient).GetAwaiter().GetResult(); progress.Next("Uploading " + manifest.Layers[cur].Digest + " layer to " + output.Repository); progress.Next("Uploaded " + manifest.Layers[cur].Digest + " layer to " + output.Repository); }); } if (includeConfig) { // Acquire config Blob listOfActions.Add(() => { var progress = new ProgressBar(3); progress.Next("Downloading config blob from " + origin.Repository); var configBlob = originClient.GetBlobAsync(origin.Repository, manifest.Config.Digest).GetAwaiter().GetResult(); progress.Next("Uploading config blob to " + output.Repository); string digestConfig = UploadLayer(configBlob, output.Repository, outputClient).GetAwaiter().GetResult(); progress.Next("Uploaded config blob to " + output); }); } var options = new ParallelOptions { MaxDegreeOfParallelism = MaxParallel }; Parallel.Invoke(options, listOfActions.ToArray()); }
private static async Task BuildDotNetImage(string fileOrigin, ImageRef outputRepo) { // 1. Upload the .Net files to the specified repository var oras = new OrasPush() { OrasExe = "C:/ProgramData/Fish/Barrel/oras/0.6.0/oras.exe", Registry = outputRepo.Registry, Tag = outputRepo.Tag, Repository = outputRepo.Repository, PublishDir = fileOrigin, Username = outputRepo.Username, Password = outputRepo.Password }; if (!oras.Execute()) { throw new Exception("Could not upload " + fileOrigin); } var clientCredentials = new AcrClientCredentials(AcrClientCredentials.LoginMode.Basic, outputRepo.Registry, outputRepo.Username, outputRepo.Password); var client = new AzureContainerRegistryClient(clientCredentials) { LoginUri = "https://" + outputRepo.Registry }; // 2. Acquire the resulting OCI manifest string orasDigest = oras.digest; ManifestWrapper manifest = await client.GetManifestAsync(outputRepo.Repository, orasDigest, "application/vnd.oci.image.manifest.v1+json"); long app_size = (long)manifest.Layers[0].Size; string appDiffId = (string)manifest.Layers[0].Annotations.AdditionalProperties["io.deis.oras.content.digest"]; string app_digest = manifest.Layers[0].Digest; // 3. Acquire base for .Net image var baseLayers = new ImageRef() { Registry = "mcr.microsoft.com" }; var dotnetVersion = "2.2"; switch (dotnetVersion) { case "2.1": baseLayers.Repository = "dotnet/core/runtime"; baseLayers.Tag = "2.1"; break; case "2.2": baseLayers.Repository = "dotnet/core/runtime"; baseLayers.Tag = "2.2"; break; case "3.0": baseLayers.Repository = "dotnet/core-nightly/runtime"; baseLayers.Tag = "3.0"; break; default: baseLayers.Repository = "dotnet/core-nightly/runtime-deps"; baseLayers.Tag = "latest"; break; } // 4. Move base layers to repo await CopyBaseImageLayers(baseLayers, outputRepo, true); // 5. Acquire config blob from base var baseClient = new AzureContainerRegistryClient(new TokenCredentials()) { LoginUri = "https://" + baseLayers.Registry }; ManifestWrapper baseManifest = await baseClient.GetManifestAsync(baseLayers.Repository, baseLayers.Tag, "application/vnd.docker.distribution.manifest.v2+json"); var configBlob = await baseClient.GetBlobAsync(baseLayers.Repository, baseManifest.Config.Digest); long appConfigSize; string appConfigDigest; // 6. Add layer to config blob using (StreamReader reader = new StreamReader(configBlob, Encoding.UTF8)) { string originalBlob = reader.ReadToEnd(); var nah = System.Text.Encoding.UTF8.GetByteCount(originalBlob); var config = JsonConvert.DeserializeObject <ConfigBlob>(originalBlob); config.Rootfs.DiffIds.Add(appDiffId); string serialized = JsonConvert.SerializeObject(config, Formatting.None); appConfigSize = Encoding.UTF8.GetByteCount(serialized); appConfigDigest = ComputeDigest(serialized); await UploadLayer(GenerateStreamFromString(serialized), outputRepo.Repository, client); // Upload config blob } // 7. Modify manifest file for the new layer var newManifest = baseManifest; newManifest.Config.Size = appConfigSize; newManifest.Config.Digest = appConfigDigest; var newLayer = new Descriptor() { MediaType = "application/vnd.docker.image.rootfs.diff.tar.gzip", Size = app_size, Digest = app_digest }; newManifest.Layers.Add(newLayer); await client.CreateManifestAsync(outputRepo.Repository, outputRepo.Tag, newManifest); // 8. Upload config blob // 9. Push new manifest // Image can now be run! }
/// <summary> /// Uploads a specified image layer by layer from another local repository (Within the specific registry) /// </summary> private static async Task BuildImageInRepoAfterDownload(string origin, string output, string outputTag, AzureContainerRegistryClient client, CancellationToken ct) { V2Manifest manifest = (V2Manifest)await client.GetManifestAsync(origin, outputTag, "application/vnd.docker.distribution.manifest.v2+json", ct); var listOfActions = new List <Action>(); // Acquire and upload all layers for (int i = 0; i < manifest.Layers.Count; i++) { var cur = i; listOfActions.Add(() => { var progress = new ProgressBar(3); progress.Refresh(0, "Starting"); var layer = client.GetBlobAsync(origin, manifest.Layers[cur].Digest).GetAwaiter().GetResult(); progress.Next("Downloading " + manifest.Layers[cur].Digest + " layer from " + origin); string digestLayer = UploadLayer(layer, output, client).GetAwaiter().GetResult(); progress.Next("Uploading " + manifest.Layers[cur].Digest + " layer to " + output); manifest.Layers[cur].Digest = digestLayer; progress.Next("Uploaded " + manifest.Layers[cur].Digest + " layer to " + output); }); } // Acquire config Blob listOfActions.Add(() => { var progress = new ProgressBar(3); progress.Next("Downloading config blob from " + origin); var configBlob = client.GetBlobAsync(origin, manifest.Config.Digest).GetAwaiter().GetResult(); progress.Next("Uploading config blob to " + output); string digestConfig = UploadLayer(configBlob, output, client).GetAwaiter().GetResult(); progress.Next("Uploaded config blob to " + output); manifest.Config.Digest = digestConfig; }); var options = new ParallelOptions { MaxDegreeOfParallelism = MaxParallel }; Parallel.Invoke(options, listOfActions.ToArray()); Console.WriteLine("Pushing new manifest to " + output + ":" + outputTag); await client.CreateManifestAsync(output, outputTag, manifest, ct); Console.WriteLine("Successfully created " + output + ":" + outputTag); }